summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThibault Meunier <thibault.meunier@isode.com>2016-07-18 09:03:55 (GMT)
committerKevin Smith <kevin.smith@isode.com>2017-02-20 15:58:04 (GMT)
commit9fe83ff62fb48662df7920afc0be71d04dafe3e4 (patch)
tree4805c1e1c0f41145bb4b97dd5e1314294e4c71b8 /BuildTools
parent407a266b8de87c8cd35b3ab4d0fede20786d4944 (diff)
downloadswift-9fe83ff62fb48662df7920afc0be71d04dafe3e4.zip
swift-9fe83ff62fb48662df7920afc0be71d04dafe3e4.tar.bz2
New Unicode Emojis Dialog
The new selector behaves like the old one. However, selection of an emoji results in the corresponding UTF-8 sequence to be inserted into the input widget instead of a ASCII emoticon. The code is based on the Emojione library which is MIT licensed. Emojione provides a mapping from shortnames to relevant Unicode codepoint, as well as mappings from textual emoticons (e.g. ). This commit does not modify the existing emoticon parser and so does not include any ability to enter emojis via text entry. The part of the Emojione library required to generate the mappings in C++ is included in this patch, specifically the emoji.json file. It is used to generate a corresponding .cpp file. Mapping code can be generated as follows: * cd BuildTools/EmojisGenerator/ * (optional) update emoji.json from https://github.com/Ranks/emojione/blob/master/emoji.json) - Version used with this commit: ba845a7 * npm install * node generate.js Test-information: General * Click the emoji button opens the selector * Change tab * Click an emoji and check it appears correctly * Click outside emoji dialog hides it Emojis * Emojis are well printed on macOS with Qt 5.7.1 * Emojis are black/white on Windows 10 with Qt 5.7.1 * Emojis have the right tooltip (when mouse is hover) * Check emojis are rendered appropriately by the receiving client Tabs * Tabs have the right tooltip * Click an emoji adds to recent tab * Emojis in the Recent tab are ordered by last click date (with a maximum of 50 "recent" emojis) * Recent emojis are saved in the QtSetting under "recentEmojis" Change-Id: Ibd07b8713d6272da6a8a4c9c35ddf866473f662b
Diffstat (limited to 'BuildTools')
-rw-r--r--BuildTools/EmojisGenerator/EmojiMapper.cpp79
-rw-r--r--BuildTools/EmojisGenerator/generate.js100
-rw-r--r--BuildTools/EmojisGenerator/package.json7
3 files changed, 186 insertions, 0 deletions
diff --git a/BuildTools/EmojisGenerator/EmojiMapper.cpp b/BuildTools/EmojisGenerator/EmojiMapper.cpp
new file mode 100644
index 0000000..be1c811
--- /dev/null
+++ b/BuildTools/EmojisGenerator/EmojiMapper.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2016-2017 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#include <SwifTools/EmojiMapper.h>
+
+#include <string>
+#include <unordered_map>
+
+namespace Swift {
+
+ //AUTO-GENERATED CONTENT
+ <%= mapping %>
+
+ std::vector<std::string> EmojiMapper::getCategories() {
+ std::vector<std::string> categories;
+ for (const auto& keyValuePair : emojisInCategory) {
+ categories.push_back(keyValuePair.first);
+ }
+ return categories;
+ }
+
+ std::string EmojiMapper::shortnameToUnicode(const std::string& shortname) {
+ auto unicodeSequenceIterator = shortnameUnicode.find(shortname);
+ if (unicodeSequenceIterator != shortnameUnicode.end()) {
+ return unicodeSequenceIterator->second;
+ }
+ else {
+ return std::string();
+ }
+ }
+
+ std::string EmojiMapper::unicodeToShortname(const std::string& unicode) {
+ auto shortnameIterator = unicodeShortname.find(unicode);
+ if (shortnameIterator != unicodeShortname.end()) {
+ return shortnameIterator->second;
+ }
+ else {
+ return std::string();
+ }
+ }
+
+ std::vector<std::string> EmojiMapper::categoryNameToEmojis(const std::string& categoryName) {
+ auto emojiIterator = emojisInCategory.find(categoryName);
+ if (emojiIterator != emojisInCategory.end()) {
+ return emojiIterator->second;
+ }
+ else {
+ return std::vector<std::string>();
+ }
+ }
+
+ std::string EmojiMapper::categoryToFlagshipUnicodeEmoji(const std::string& category) {
+ if (category == "recent") {
+ return shortnameToUnicode(":clock3:");
+ } else if (category == "people") {
+ return shortnameToUnicode(":smiley:");
+ } else if (category == "nature" ) {
+ return shortnameToUnicode(":dog:");
+ } else if (category == "food") {
+ return shortnameToUnicode(":apple:");
+ } else if (category == "activity") {
+ return shortnameToUnicode(":soccer:");
+ } else if (category == "travel") {
+ return shortnameToUnicode(":red_car:");
+ } else if (category == "objects") {
+ return shortnameToUnicode(":bulb:");
+ } else if (category == "symbols") {
+ return shortnameToUnicode(":heavy_division_sign:");
+ } else if (category == "regional") {
+ return shortnameToUnicode(":regional_indicator_a:");
+ } else if (category == "flags") {
+ return shortnameToUnicode(":flag_white:");
+ }
+ return std::string();
+ }
+}
diff --git a/BuildTools/EmojisGenerator/generate.js b/BuildTools/EmojisGenerator/generate.js
new file mode 100644
index 0000000..2b5541f
--- /dev/null
+++ b/BuildTools/EmojisGenerator/generate.js
@@ -0,0 +1,100 @@
+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>{' + _(emojis).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) {
+ // 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);
diff --git a/BuildTools/EmojisGenerator/package.json b/BuildTools/EmojisGenerator/package.json
new file mode 100644
index 0000000..8b719ba
--- /dev/null
+++ b/BuildTools/EmojisGenerator/package.json
@@ -0,0 +1,7 @@
+{
+ "name": "emojione-android",
+ "version": "0.1.0",
+ "dependencies": {
+ "underscore": "^1.7.0"
+ }
+}