1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
|
var util = require("util"),
fs = require("fs"),
_ = require("underscore");
// Load emojis
var emojis = require("./emoji.json");
var unicodeCodepointToByteArray = function (codepoint) {
var utf8 = unescape(encodeURIComponent(String.fromCodePoint(parseInt(codepoint, 16))));
var arr = [];
for (var i = 0; i < utf8.length; i++) {
arr.push(utf8.charCodeAt(i));
}
return arr;
}
var byteArrayToCStringLiteral = function (byteArray) {
var literalString = "";
for (var i = 0; i < byteArray.length; i++) {
literalString += "\\x" + byteArray[i].toString(16);
}
return literalString;
}
var mapping = '';
// Generate C++ mapping for shortnameUnicode_
mapping += 'const std::unordered_map<std::string, std::string> EmojiMapper::shortnameUnicode = std::unordered_map<std::string, std::string>{';
mapping += _(emojis).filter(function(data) {
// Filter out regional category.
return data.category != 'regional';
}).filter(function(data) {
// Only use emojis with 2 or less codepoints, as Qt's harfbuzz version
// has issues rendering those as a single glyph.
return data.unicode.split("-").length < 3;
}).map(function(data) {
var shortname = data.shortname;
// Get codepoints
var codepoints = _(data.unicode.split("-")).map(function (code) {
//return "\\U" + "0".repeat(8-code.length) + code;
return byteArrayToCStringLiteral(unicodeCodepointToByteArray(code));
});
// .join('\\U0000200D') -> join characters with a zero width joiner, required by
// some emojis pattern (:family_mwg: for example)
// Currently do no join them by a ZWJ as it breaks rendering of a lot simple emojis
// like $EMOJI followed by skin tone modifier.
//return '{"' + shortname + '", "' + codepoints.join(byteArrayToCStringLiteral(unicodeCodepointToByteArray('200D'))) + '"}';
return '{"' + shortname + '", "' + codepoints.join("") + '"}';
}).join(", ") + '};\n\n';
// Generate C++ code for the reverse mapping (i.e. unicodeShortname_ )
mapping += ' const std::unordered_map<std::string, std::string> EmojiMapper::unicodeShortname = [](){\n' +
' std::unordered_map<std::string, std::string> unicodeSequenceToShortname;\n' +
' const auto& shortnameToUnicodeMap = EmojiMapper::shortnameUnicode;\n' +
' for (const auto& shortnameToUnicode : shortnameToUnicodeMap) {\n' +
' unicodeSequenceToShortname[shortnameToUnicode.second] = shortnameToUnicode.first;\n' +
' }\n' +
' return unicodeSequenceToShortname;\n' +
' }();\n\n';
// Generate C++ mapping for categories
var CategoryMapping = new Map();
_(emojis).filter(function(data) {
// Filter out regional category.
return data.category != 'regional';
}).filter(function(data) {
// Only use emojis with 2 or less codepoints, as Qt's harfbuzz version
// has issues rendering those as a single glyph.
return data.unicode.split("-").length < 3;
}).map(function(data, category) {
// Get codepoints
var codepoints = _(data.unicode.split("-")).map(function (code) {
//return "\\U" + "0".repeat(8-code.length) + code;
return byteArrayToCStringLiteral(unicodeCodepointToByteArray(code));
});
if (!CategoryMapping.has(data.category)) {
CategoryMapping = CategoryMapping.set(data.category, []);
}
//CategoryMapping.get(data.category).push(codepoints.join(byteArrayToCStringLiteral(unicodeCodepointToByteArray('200D'))));
// Currently do no join them by a ZWJ as it breaks rendering of a lot simple emojis
// like $EMOJI followed by skin tone modifier.
CategoryMapping.get(data.category).push(codepoints.join(""));
//return 'categories_["' + data.category + '"].push_back("' + codepoints.join('\\U0000200D') + '");';
});
mapping += ' const std::unordered_map<std::string, std::vector<std::string>> EmojiMapper::emojisInCategory = std::unordered_map<std::string, std::vector<std::string>>{';
categoryMappings = [];
for (var category of CategoryMapping.keys()) {
categoryMappings.push('{"' + category + '", {' + CategoryMapping.get(category).map(function (literal) {
return '"' + literal + '"';
}).join(', ') + '}}')
}
mapping += categoryMappings.join(', ');
mapping += '};\n'
mapping.replace(/^\s*\n/gm, '');
// Generate C++ class from template
var input = fs.readFileSync("./EmojiMapper.cpp");
var output = _(input.toString()).template()({ mapping: mapping });
// Write C++ class to file
var output_path = "../../SwifTools/EmojiMapper.cpp";
fs.writeFileSync(output_path, output);
console.log("Generated " + output_path);
|