1 #include "..\..\..\StdAfx.h"
3 #include "texture_atlas.h"
4 #include "texture_font.h"
11 namespace caspar { namespace core { namespace text {
13 struct freetype_exception : virtual caspar_exception
15 freetype_exception() {}
16 explicit freetype_exception(const char* msg) : caspar_exception(msg) {}
21 unicode_range() : first(0), last(0) {}
22 unicode_range(int f, int l) : first(f), last(l) {}
28 unicode_range get_range(unicode_block block);
31 struct texture_font::impl
36 glyph_info(int w, int h, float l, float t, float r, float b) : width(w), height(h), left(l), top(t), right(r), bottom(b)
39 float left, top, right, bottom;
49 std::map<int, glyph_info> glyphs_;
52 impl::impl(texture_atlas& atlas, const text_info& info, bool normalize_coordinates) : lib_(nullptr), face_(nullptr), atlas_(atlas), size_(info.size), tracking_(info.size*info.tracking/1000.0f), normalize_(normalize_coordinates)
57 err = FT_Init_FreeType(&lib_);
58 if(err) throw freetype_exception("Failed to initialize freetype");
60 err = FT_New_Face(lib_, u8(info.font_file).c_str(), 0, &face_);
61 if(err) throw freetype_exception("Failed to load font");
63 err = FT_Set_Char_Size(face_, static_cast<FT_F26Dot6>(size_*64), 0, 72, 72);
64 if(err) throw freetype_exception("Failed to set font size");
66 catch(std::exception& ex)
71 FT_Done_FreeType(lib_);
82 FT_Done_FreeType(lib_);
85 void set_tracking(int tracking)
87 tracking_ = size_ * tracking / 1000.0f;
90 int count_glyphs_in_range(unicode_block block)
92 unicode_range range = get_range(block);
94 //TODO: extract info from freetype
96 //very pesimistic, assumes a glyph for each charcode
97 return range.last - range.first;
100 void impl::load_glyphs(unicode_block block, const color<float>& col)
103 int flags = FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_NORMAL;
104 unicode_range range = get_range(block);
106 for(int i = range.first; i <= range.last; ++i)
108 FT_UInt glyph_index = FT_Get_Char_Index(face_, i);
109 if(!glyph_index) //ignore codes that doesn't have a glyph for now. Might want to map these to a special glyph later.
112 err = FT_Load_Glyph(face_, glyph_index, flags);
113 if(err) continue; //igonore glyphs that fail to load
115 const FT_Bitmap& bitmap = face_->glyph->bitmap; //shorthand notation
117 auto region = atlas_.get_region(bitmap.width+1, bitmap.rows+1);
120 //the glyph doesn't fit in the texture-atlas. ignore it for now.
121 //we might want to restart with a bigger atlas in the future
125 atlas_.set_region(region.x, region.y, bitmap.width, bitmap.rows, bitmap.buffer, bitmap.pitch, col);
126 glyphs_.insert(std::pair<int, glyph_info>(i, glyph_info(bitmap.width, bitmap.rows,
127 region.x / (float)atlas_.width(),
128 region.y / (float)atlas_.height(),
129 (region.x + bitmap.width) / (float)atlas_.width(),
130 (region.y + bitmap.rows) / (float)atlas_.height())));
134 std::vector<float> create_vertex_stream(const std::wstring& str, int x, int y, int parent_width, int parent_height, string_metrics* metrics)
136 //TODO: detect glyphs that aren't in the atlas and load them (and maybe that entire unicode_block on the fly
138 std::vector<float> result(16*str.length(), 0);
140 bool use_kerning = (face_->face_flags & FT_FACE_FLAG_KERNING) == FT_FACE_FLAG_KERNING;
142 FT_UInt previous = 0;
143 float pos_x = (float)x;
144 float pos_y = (float)y;
147 int maxProtrudeUnderY = 0;
150 auto end = str.end();
151 for(auto it = str.begin(); it != end; ++it, ++index)
153 auto glyph_it = glyphs_.find(*it);
154 if(glyph_it != glyphs_.end())
156 const glyph_info& coords = glyph_it->second;
158 FT_UInt glyph_index = FT_Get_Char_Index(face_, (*it));
160 if(use_kerning && previous && glyph_index)
163 FT_Get_Kerning(face_, previous, glyph_index, FT_KERNING_DEFAULT, &delta);
165 pos_x += delta.x / 64.0f;
168 FT_Load_Glyph(face_, glyph_index, FT_LOAD_NO_BITMAP | FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_NORMAL);
170 float left = (pos_x + face_->glyph->metrics.horiBearingX/64.0f) / parent_width ;
171 float right = ((pos_x + face_->glyph->metrics.horiBearingX/64.0f) + coords.width) / parent_width;
173 float top = (pos_y - face_->glyph->metrics.horiBearingY/64.0f) / parent_height;
174 float bottom = ((pos_y - face_->glyph->metrics.horiBearingY/64.0f) + coords.height) / parent_height;
177 result[index*16 + 0] = left; //vertex.x
178 result[index*16 + 1] = top; //vertex.y
179 result[index*16 + 2] = coords.left; //texcoord.r
180 result[index*16 + 3] = coords.top; //texcoord.s
183 result[index*16 + 4] = right; //vertex.x
184 result[index*16 + 5] = top; //vertex.y
185 result[index*16 + 6] = coords.right; //texcoord.r
186 result[index*16 + 7] = coords.top; //texcoord.s
188 //vertex 3 bottom right
189 result[index*16 + 8] = right; //vertex.x
190 result[index*16 + 9] = bottom; //vertex.y
191 result[index*16 + 10] = coords.right; //texcoord.r
192 result[index*16 + 11] = coords.bottom; //texcoord.s
194 //vertex 4 bottom left
195 result[index*16 + 12] = left; //vertex.x
196 result[index*16 + 13] = bottom; //vertex.y
197 result[index*16 + 14] = coords.left; //texcoord.r
198 result[index*16 + 15] = coords.bottom; //texcoord.s
200 int bearingY = face_->glyph->metrics.horiBearingY >> 6;
202 if(bearingY > maxBearingY)
203 maxBearingY = bearingY;
205 int protrudeUnderY = coords.height - bearingY;
207 if (protrudeUnderY > maxProtrudeUnderY)
208 maxProtrudeUnderY = protrudeUnderY;
210 if (maxBearingY + maxProtrudeUnderY > maxHeight)
211 maxHeight = maxBearingY + maxProtrudeUnderY;
213 pos_x += face_->glyph->advance.x / 64.0f;
215 previous = glyph_index;
219 //TODO: maybe we should try to load the glyph on the fly if it is missing.
225 float ratio_x = parent_width/(pos_x - x);
226 float ratio_y = parent_height/(float)(maxHeight);
227 for(index = 0; index < result.size(); index += 4)
229 result[index + 0] *= ratio_x;
230 result[index + 1] *= ratio_y;
234 if(metrics != nullptr)
236 metrics->width = (int)(pos_x - x + 0.5f);
237 metrics->bearingY = maxBearingY;
238 metrics->height = maxHeight;
239 metrics->protrudeUnderY = maxProtrudeUnderY;
244 string_metrics measure_string(const std::wstring& str)
246 string_metrics result;
248 bool use_kerning = (face_->face_flags & FT_FACE_FLAG_KERNING) == FT_FACE_FLAG_KERNING;
250 FT_UInt previous = 0;
254 auto end = str.end();
255 for(auto it = str.begin(); it != end; ++it, ++index)
257 auto glyph_it = glyphs_.find(*it);
258 if(glyph_it != glyphs_.end())
260 const glyph_info& coords = glyph_it->second;
262 FT_UInt glyph_index = FT_Get_Char_Index(face_, (*it));
264 if(use_kerning && previous && glyph_index)
267 FT_Get_Kerning(face_, previous, glyph_index, FT_KERNING_DEFAULT, &delta);
269 pos_x += delta.x / 64.0f;
272 FT_Load_Glyph(face_, glyph_index, FT_LOAD_NO_BITMAP | FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_NORMAL);
274 int bearingY = face_->glyph->metrics.horiBearingY >> 6;
275 if(bearingY > result.bearingY)
276 result.bearingY = bearingY;
278 int protrudeUnderY = coords.height - bearingY;
280 if (protrudeUnderY > result.protrudeUnderY)
281 result.protrudeUnderY = protrudeUnderY;
283 if (result.bearingY + result.protrudeUnderY > result.height)
284 result.height = result.bearingY + result.protrudeUnderY;
286 pos_x += face_->glyph->advance.x / 64.0f;
287 previous = glyph_index;
291 result.width = (int)(pos_x+.5f);
296 texture_font::texture_font(texture_atlas& atlas, const text_info& info, bool normalize_coordinates) : impl_(new impl(atlas, info, normalize_coordinates)) {}
297 void texture_font::load_glyphs(unicode_block range, const color<float>& col) { impl_->load_glyphs(range, col); }
298 void texture_font::set_tracking(int tracking) { impl_->set_tracking(tracking); }
299 std::vector<float> texture_font::create_vertex_stream(const std::wstring& str, int x, int y, int parent_width, int parent_height, string_metrics* metrics) { return impl_->create_vertex_stream(str, x, y, parent_width, parent_height, metrics); }
300 string_metrics texture_font::measure_string(const std::wstring& str) { return impl_->measure_string(str); }
302 unicode_range get_range(unicode_block block)
306 case Basic_Latin: return unicode_range(0x0000, 0x007F);
307 case Latin_1_Supplement: return unicode_range(0x0080, 0x00FF);
308 case Latin_Extended_A: return unicode_range(0x0100, 0x017F);
309 case Latin_Extended_B: return unicode_range(0x0180, 0x024F);
310 case IPA_Extensions: return unicode_range(0x0250, 0x02AF);
311 case Spacing_Modifier_Letters: return unicode_range(0x02B0, 0x02FF);
312 case Combining_Diacritical_Marks: return unicode_range(0x0300, 0x036F);
313 case Greek_and_Coptic: return unicode_range(0x0370, 0x03FF);
314 case Cyrillic: return unicode_range(0x0400, 0x04FF);
315 case Cyrillic_Supplement: return unicode_range(0x0500, 0x052F);
316 case Armenian: return unicode_range(0x0530, 0x058F);
317 case Hebrew: return unicode_range(0x0590, 0x05FF);
318 case Arabic: return unicode_range(0x0600, 0x06FF);
319 case Syriac: return unicode_range(0x0700, 0x074F);
320 case Arabic_Supplement: return unicode_range(0x0750, 0x077F);
321 case Thaana: return unicode_range(0x0780, 0x07BF);
322 case NKo: return unicode_range(0x07C0, 0x07FF);
323 case Samaritan: return unicode_range(0x0800, 0x083F);
324 case Mandaic: return unicode_range(0x0840, 0x085F);
325 case Arabic_Extended_A: return unicode_range(0x08A0, 0x08FF);
326 case Devanagari: return unicode_range(0x0900, 0x097F);
327 case Bengali: return unicode_range(0x0980, 0x09FF);
328 case Gurmukhi: return unicode_range(0x0A00, 0x0A7F);
329 case Gujarati: return unicode_range(0x0A80, 0x0AFF);
330 case Oriya: return unicode_range(0x0B00, 0x0B7F);
331 case Tamil: return unicode_range(0x0B80, 0x0BFF);
332 case Telugu: return unicode_range(0x0C00, 0x0C7F);
333 case Kannada: return unicode_range(0x0C80, 0x0CFF);
334 case Malayalam: return unicode_range(0x0D00, 0x0D7F);
335 case Sinhala: return unicode_range(0x0D80, 0x0DFF);
336 case Thai: return unicode_range(0x0E00, 0x0E7F);
337 case Lao: return unicode_range(0x0E80, 0x0EFF);
338 case Tibetan: return unicode_range(0x0F00, 0x0FFF);
339 case Myanmar: return unicode_range(0x1000, 0x109F);
340 case Georgian: return unicode_range(0x10A0, 0x10FF);
341 case Hangul_Jamo: return unicode_range(0x1100, 0x11FF);
342 case Ethiopic: return unicode_range(0x1200, 0x137F);
343 case Ethiopic_Supplement: return unicode_range(0x1380, 0x139F);
344 case Cherokee: return unicode_range(0x13A0, 0x13FF);
345 case Unified_Canadian_Aboriginal_Syllabics: return unicode_range(0x1400, 0x167F);
346 case Ogham: return unicode_range(0x1680, 0x169F);
347 case Runic: return unicode_range(0x16A0, 0x16FF);
348 case Tagalog: return unicode_range(0x1700, 0x171F);
349 case Hanunoo: return unicode_range(0x1720, 0x173F);
350 case Buhid: return unicode_range(0x1740, 0x175F);
351 case Tagbanwa: return unicode_range(0x1760, 0x177F);
352 case Khmer: return unicode_range(0x1780, 0x17FF);
353 case Mongolian: return unicode_range(0x1800, 0x18AF);
354 case Unified_Canadian_Aboriginal_Syllabics_Extended: return unicode_range(0x18B0, 0x18FF);
355 case Limbu: return unicode_range(0x1900, 0x194F);
356 case Tai_Le: return unicode_range(0x1950, 0x197F);
357 case New_Tai_Lue: return unicode_range(0x1980, 0x19DF);
358 case Khmer_Symbols: return unicode_range(0x19E0, 0x19FF);
359 case Buginese: return unicode_range(0x1A00, 0x1A1F);
360 case Tai_Tham: return unicode_range(0x1A20, 0x1AAF);
361 case Balinese: return unicode_range(0x1B00, 0x1B7F);
362 case Sundanese: return unicode_range(0x1B80, 0x1BBF);
363 case Batak: return unicode_range(0x1BC0, 0x1BFF);
364 case Lepcha: return unicode_range(0x1C00, 0x1C4F);
365 case Ol_Chiki: return unicode_range(0x1C50, 0x1C7F);
366 case Sundanese_Supplement: return unicode_range(0x1CC0, 0x1CCF);
367 case Vedic_Extensions: return unicode_range(0x1CD0, 0x1CFF);
368 case Phonetic_Extensions: return unicode_range(0x1D00, 0x1D7F);
369 case Phonetic_Extensions_Supplement: return unicode_range(0x1D80, 0x1DBF);
370 case Combining_Diacritical_Marks_Supplement: return unicode_range(0x1DC0, 0x1DFF);
371 case Latin_Extended_Additional: return unicode_range(0x1E00, 0x1EFF);
372 case Greek_Extended: return unicode_range(0x1F00, 0x1FFF);
373 case General_Punctuation: return unicode_range(0x2000, 0x206F);
374 case Superscripts_and_Subscripts: return unicode_range(0x2070, 0x209F);
375 case Currency_Symbols: return unicode_range(0x20A0, 0x20CF);
376 case Combining_Diacritical_Marks_for_Symbols: return unicode_range(0x20D0, 0x20FF);
377 case Letterlike_Symbols: return unicode_range(0x2100, 0x214F);
378 case Number_Forms: return unicode_range(0x2150, 0x218F);
379 case Arrows: return unicode_range(0x2190, 0x21FF);
380 case Mathematical_Operators: return unicode_range(0x2200, 0x22FF);
381 case Miscellaneous_Technical: return unicode_range(0x2300, 0x23FF);
382 case Control_Pictures: return unicode_range(0x2400, 0x243F);
383 case Optical_Character_Recognition: return unicode_range(0x2440, 0x245F);
384 case Enclosed_Alphanumerics: return unicode_range(0x2460, 0x24FF);
385 case Box_Drawing: return unicode_range(0x2500, 0x257F);
386 case Block_Elements: return unicode_range(0x2580, 0x259F);
387 case Geometric_Shapes: return unicode_range(0x25A0, 0x25FF);
388 case Miscellaneous_Symbols: return unicode_range(0x2600, 0x26FF);
389 case Dingbats: return unicode_range(0x2700, 0x27BF);
390 case Miscellaneous_Mathematical_Symbols_A: return unicode_range(0x27C0, 0x27EF);
391 case Supplemental_Arrows_A: return unicode_range(0x27F0, 0x27FF);
392 case Braille_Patterns: return unicode_range(0x2800, 0x28FF);
393 case Supplemental_Arrows_B: return unicode_range(0x2900, 0x297F);
394 case Miscellaneous_Mathematical_Symbols_B: return unicode_range(0x2980, 0x29FF);
395 case Supplemental_Mathematical_Operators: return unicode_range(0x2A00, 0x2AFF);
396 case Miscellaneous_Symbols_and_Arrows: return unicode_range(0x2B00, 0x2BFF);
397 case Glagolitic: return unicode_range(0x2C00, 0x2C5F);
398 case Latin_Extended_C: return unicode_range(0x2C60, 0x2C7F);
399 case Coptic: return unicode_range(0x2C80, 0x2CFF);
400 case Georgian_Supplement: return unicode_range(0x2D00, 0x2D2F);
401 case Tifinagh: return unicode_range(0x2D30, 0x2D7F);
402 case Ethiopic_Extended: return unicode_range(0x2D80, 0x2DDF);
403 case Cyrillic_Extended_A: return unicode_range(0x2DE0, 0x2DFF);
404 case Supplemental_Punctuation: return unicode_range(0x2E00, 0x2E7F);
405 case CJK_Radicals_Supplement: return unicode_range(0x2E80, 0x2EFF);
406 case Kangxi_Radicals: return unicode_range(0x2F00, 0x2FDF);
407 case Ideographic_Description_Characters: return unicode_range(0x2FF0, 0x2FFF);
408 case CJK_Symbols_and_Punctuation: return unicode_range(0x3000, 0x303F);
409 case Hiragana: return unicode_range(0x3040, 0x309F);
410 case Katakana: return unicode_range(0x30A0, 0x30FF);
411 case Bopomofo: return unicode_range(0x3100, 0x312F);
412 case Hangul_Compatibility_Jamo: return unicode_range(0x3130, 0x318F);
413 case Kanbun: return unicode_range(0x3190, 0x319F);
414 case Bopomofo_Extended: return unicode_range(0x31A0, 0x31BF);
415 case CJK_Strokes: return unicode_range(0x31C0, 0x31EF);
416 case Katakana_Phonetic_Extensions: return unicode_range(0x31F0, 0x31FF);
417 case Enclosed_CJK_Letters_and_Months: return unicode_range(0x3200, 0x32FF);
418 case CJK_Compatibility: return unicode_range(0x3300, 0x33FF);
419 case CJK_Unified_Ideographs_Extension_A: return unicode_range(0x3400, 0x4DBF);
420 case Yijing_Hexagram_Symbols: return unicode_range(0x4DC0, 0x4DFF);
421 case CJK_Unified_Ideographs: return unicode_range(0x4E00, 0x9FFF);
422 case Yi_Syllables: return unicode_range(0xA000, 0xA48F);
423 case Yi_Radicals: return unicode_range(0xA490, 0xA4CF);
424 case Lisu: return unicode_range(0xA4D0, 0xA4FF);
425 case Vai: return unicode_range(0xA500, 0xA63F);
426 case Cyrillic_Extended_B: return unicode_range(0xA640, 0xA69F);
427 case Bamum: return unicode_range(0xA6A0, 0xA6FF);
428 case Modifier_Tone_Letters: return unicode_range(0xA700, 0xA71F);
429 case Latin_Extended_D: return unicode_range(0xA720, 0xA7FF);
430 case Syloti_Nagri: return unicode_range(0xA800, 0xA82F);
431 case Common_Indic_Number_Forms: return unicode_range(0xA830, 0xA83F);
432 case Phags_pa: return unicode_range(0xA840, 0xA87F);
433 case Saurashtra: return unicode_range(0xA880, 0xA8DF);
434 case Devanagari_Extended: return unicode_range(0xA8E0, 0xA8FF);
435 case Kayah_Li: return unicode_range(0xA900, 0xA92F);
436 case Rejang: return unicode_range(0xA930, 0xA95F);
437 case Hangul_Jamo_Extended_A: return unicode_range(0xA960, 0xA97F);
438 case Javanese: return unicode_range(0xA980, 0xA9DF);
439 case Cham: return unicode_range(0xAA00, 0xAA5F);
440 case Myanmar_Extended_A: return unicode_range(0xAA60, 0xAA7F);
441 case Tai_Viet: return unicode_range(0xAA80, 0xAADF);
442 case Meetei_Mayek_Extensions: return unicode_range(0xAAE0, 0xAAFF);
443 case Ethiopic_Extended_A: return unicode_range(0xAB00, 0xAB2F);
444 case Meetei_Mayek: return unicode_range(0xABC0, 0xABFF);
445 case Hangul_Syllables: return unicode_range(0xAC00, 0xD7AF);
446 case Hangul_Jamo_Extended_B: return unicode_range(0xD7B0, 0xD7FF);
447 case High_Surrogates: return unicode_range(0xD800, 0xDB7F);
448 case High_Private_Use_Surrogates: return unicode_range(0xDB80, 0xDBFF);
449 case Low_Surrogates: return unicode_range(0xDC00, 0xDFFF);
450 case Private_Use_Area: return unicode_range(0xE000, 0xF8FF);
451 case CJK_Compatibility_Ideographs: return unicode_range(0xF900, 0xFAFF);
452 case Alphabetic_Presentation_Forms: return unicode_range(0xFB00, 0xFB4F);
453 case Arabic_Presentation_Forms_A: return unicode_range(0xFB50, 0xFDFF);
454 case Variation_Selectors: return unicode_range(0xFE00, 0xFE0F);
455 case Vertical_Forms: return unicode_range(0xFE10, 0xFE1F);
456 case Combining_Half_Marks: return unicode_range(0xFE20, 0xFE2F);
457 case CJK_Compatibility_Forms: return unicode_range(0xFE30, 0xFE4F);
458 case Small_Form_Variants: return unicode_range(0xFE50, 0xFE6F);
459 case Arabic_Presentation_Forms_B: return unicode_range(0xFE70, 0xFEFF);
460 case Halfwidth_and_Fullwidth_Forms: return unicode_range(0xFF00, 0xFFEF);
461 case Specials: return unicode_range(0xFFF0, 0xFFFF);
462 case Linear_B_Syllabary: return unicode_range(0x10000, 0x1007F);
463 case Linear_B_Ideograms: return unicode_range(0x10080, 0x100FF);
464 case Aegean_Numbers: return unicode_range(0x10100, 0x1013F);
465 case Ancient_Greek_Numbers: return unicode_range(0x10140, 0x1018F);
466 case Ancient_Symbols: return unicode_range(0x10190, 0x101CF);
467 case Phaistos_Disc: return unicode_range(0x101D0, 0x101FF);
468 case Lycian: return unicode_range(0x10280, 0x1029F);
469 case Carian: return unicode_range(0x102A0, 0x102DF);
470 case Old_Italic: return unicode_range(0x10300, 0x1032F);
471 case Gothic: return unicode_range(0x10330, 0x1034F);
472 case Ugaritic: return unicode_range(0x10380, 0x1039F);
473 case Old_Persian: return unicode_range(0x103A0, 0x103DF);
474 case Deseret: return unicode_range(0x10400, 0x1044F);
475 case Shavian: return unicode_range(0x10450, 0x1047F);
476 case Osmanya: return unicode_range(0x10480, 0x104AF);
477 case Cypriot_Syllabary: return unicode_range(0x10800, 0x1083F);
478 case Imperial_Aramaic: return unicode_range(0x10840, 0x1085F);
479 case Phoenician: return unicode_range(0x10900, 0x1091F);
480 case Lydian: return unicode_range(0x10920, 0x1093F);
481 case Meroitic_Hieroglyphs: return unicode_range(0x10980, 0x1099F);
482 case Meroitic_Cursive: return unicode_range(0x109A0, 0x109FF);
483 case Kharoshthi: return unicode_range(0x10A00, 0x10A5F);
484 case Old_South_Arabian: return unicode_range(0x10A60, 0x10A7F);
485 case Avestan: return unicode_range(0x10B00, 0x10B3F);
486 case Inscriptional_Parthian: return unicode_range(0x10B40, 0x10B5F);
487 case Inscriptional_Pahlavi: return unicode_range(0x10B60, 0x10B7F);
488 case Old_Turkic: return unicode_range(0x10C00, 0x10C4F);
489 case Rumi_Numeral_Symbols: return unicode_range(0x10E60, 0x10E7F);
490 case Brahmi: return unicode_range(0x11000, 0x1107F);
491 case Kaithi: return unicode_range(0x11080, 0x110CF);
492 case Sora_Sompeng: return unicode_range(0x110D0, 0x110FF);
493 case Chakma: return unicode_range(0x11100, 0x1114F);
494 case Sharada: return unicode_range(0x11180, 0x111DF);
495 case Takri: return unicode_range(0x11680, 0x116CF);
496 case Cuneiform: return unicode_range(0x12000, 0x123FF);
497 case Cuneiform_Numbers_and_Punctuation: return unicode_range(0x12400, 0x1247F);
498 case Egyptian_Hieroglyphs: return unicode_range(0x13000, 0x1342F);
499 case Bamum_Supplement: return unicode_range(0x16800, 0x16A3F);
500 case Miao: return unicode_range(0x16F00, 0x16F9F);
501 case Kana_Supplement: return unicode_range(0x1B000, 0x1B0FF);
502 case Byzantine_Musical_Symbols: return unicode_range(0x1D000, 0x1D0FF);
503 case Musical_Symbols: return unicode_range(0x1D100, 0x1D1FF);
504 case Ancient_Greek_Musical_Notation: return unicode_range(0x1D200, 0x1D24F);
505 case Tai_Xuan_Jing_Symbols: return unicode_range(0x1D300, 0x1D35F);
506 case Counting_Rod_Numerals: return unicode_range(0x1D360, 0x1D37F);
507 case Mathematical_Alphanumeric_Symbols: return unicode_range(0x1D400, 0x1D7FF);
508 case Arabic_Mathematical_Alphabetic_Symbols: return unicode_range(0x1EE00, 0x1EEFF);
509 case Mahjong_Tiles: return unicode_range(0x1F000, 0x1F02F);
510 case Domino_Tiles: return unicode_range(0x1F030, 0x1F09F);
511 case Playing_Cards: return unicode_range(0x1F0A0, 0x1F0FF);
512 case Enclosed_Alphanumeric_Supplement: return unicode_range(0x1F100, 0x1F1FF);
513 case Enclosed_Ideographic_Supplement: return unicode_range(0x1F200, 0x1F2FF);
514 case Miscellaneous_Symbols_And_Pictographs: return unicode_range(0x1F300, 0x1F5FF);
515 case Emoticons: return unicode_range(0x1F600, 0x1F64F);
516 case Transport_And_Map_Symbols: return unicode_range(0x1F680, 0x1F6FF);
517 case Alchemical_Symbols: return unicode_range(0x1F700, 0x1F77F);
518 case CJK_Unified_Ideographs_Extension_B: return unicode_range(0x20000, 0x2A6DF);
519 case CJK_Unified_Ideographs_Extension_C: return unicode_range(0x2A700, 0x2B73F);
520 case CJK_Unified_Ideographs_Extension_D: return unicode_range(0x2B740, 0x2B81F);
521 case CJK_Compatibility_Ideographs_Supplement: return unicode_range(0x2F800, 0x2FA1F);
522 case Tags: return unicode_range(0xE0000, 0xE007F);
523 case Variation_Selectors_Supplement: return unicode_range(0xE0100, 0xE01EF);
524 case Supplementary_Private_Use_Area_A: return unicode_range(0xF0000, 0xFFFFF);
525 case Supplementary_Private_Use_Area_B: return unicode_range(0x100000, 0x10FFFF);
527 return unicode_range(0,0);