#!/usr/bin/python
# coding=UTF-8
#
# Copyright 2014 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Create a curated subset of NotoSansSymbols for Android."""
__author__ = 'roozbeh@google.com (Roozbeh Pournader)'
import sys
from nototools import subset
from nototools import unicode_data
# Unicode blocks that we want to include in the font
BLOCKS_TO_INCLUDE = """
20D0..20FF; Combining Diacritical Marks for Symbols
2100..214F; Letterlike Symbols
2190..21FF; Arrows
2200..22FF; Mathematical Operators
2300..23FF; Miscellaneous Technical
2400..243F; Control Pictures
2440..245F; Optical Character Recognition
2460..24FF; Enclosed Alphanumerics
2500..257F; Box Drawing
2580..259F; Block Elements
25A0..25FF; Geometric Shapes
2600..26FF; Miscellaneous Symbols
2700..27BF; Dingbats
27C0..27EF; Miscellaneous Mathematical Symbols-A
27F0..27FF; Supplemental Arrows-A
2800..28FF; Braille Patterns
2A00..2AFF; Supplemental Mathematical Operators
"""
# One-off characters to be included, needed for backward compatibility and
# supporting various character sets, including ARIB sets and black and white
# emoji
ONE_OFF_ADDITIONS = {
0x27D0, # ⟐ WHITE DIAMOND WITH CENTRED DOT
0x2934, # ⤴ ARROW POINTING RIGHTWARDS THEN CURVING UPWARDS
0x2935, # ⤵ ARROW POINTING RIGHTWARDS THEN CURVING DOWNWARDS
0x2985, # ⦅ LEFT WHITE PARENTHESIS
0x2986, # ⦆ RIGHT WHITE PARENTHESIS
0x2B05, # ⬅ LEFTWARDS BLACK ARROW
0x2B06, # ⬆ UPWARDS BLACK ARROW
0x2B07, # ⬇ DOWNWARDS BLACK ARROW
0x2B24, # ⬤ BLACK LARGE CIRCLE
0x2B2E, # ⬮ BLACK VERTICAL ELLIPSE
0x2B2F, # ⬯ WHITE VERTICAL ELLIPSE
0x2B56, # ⭖ HEAVY OVAL WITH OVAL INSIDE
0x2B57, # ⭗ HEAVY CIRCLE WITH CIRCLE INSIDE
0x2B58, # ⭘ HEAVY CIRCLE
0x2B59, # ⭙ HEAVY CIRCLED SALTIRE
}
# letter-based characters, provided by Roboto
LETTERLIKE_CHARS_IN_ROBOTO = {
0x2100, # ℀ ACCOUNT OF
0x2101, # ℁ ADDRESSED TO THE SUBJECT
0x2103, # ℃ DEGREE CELSIUS
0x2105, # ℅ CARE OF
0x2106, # ℆ CADA UNA
0x2109, # ℉ DEGREE FAHRENHEIT
0x2113, # ℓ SCRIPT SMALL L
0x2116, # № NUMERO SIGN
0x2117, # ℗ SOUND RECORDING COPYRIGHT
0x211E, # ℞ PRESCRIPTION TAKE
0x211F, # ℟ RESPONSE
0x2120, # ℠ SERVICE MARK
0x2121, # ℡ TELEPHONE SIGN
0x2122, # ™ TRADE MARK SIGN
0x2123, # ℣ VERSICLE
0x2125, # ℥ OUNCE SIGN
0x2126, # Ω OHM SIGN
0x212A, # K KELVIN SIGN
0x212B, # Å ANGSTROM SIGN
0x212E, # ℮ ESTIMATED SYMBOL
0x2132, # Ⅎ TURNED CAPITAL F
0x213B, # ℻ FACSIMILE SIGN
0x214D, # ⅍ AKTIESELSKAB
0x214F, # ⅏ SYMBOL FOR SAMARITAN SOURCE
}
# default emoji characters in the BMP, based on
# http://www.unicode.org/draft/Public/emoji/1.0/emoji-data.txt
# We exclude these, so we don't block color emoji.
BMP_DEFAULT_EMOJI = {
0x231A, # ⌚ WATCH
0x231B, # ⌛ HOURGLASS
0x23E9, # ⏩ BLACK RIGHT-POINTING DOUBLE TRIANGLE
0x23EA, # ⏪ BLACK LEFT-POINTING DOUBLE TRIANGLE
0x23EB, # ⏫ BLACK UP-POINTING DOUBLE TRIANGLE
0x23EC, # ⏬ BLACK DOWN-POINTING DOUBLE TRIANGLE
0x23F0, # ⏰ ALARM CLOCK
0x23F3, # ⏳ HOURGLASS WITH FLOWING SAND
0x25FD, # ◽ WHITE MEDIUM SMALL SQUARE
0x25FE, # ◾ BLACK MEDIUM SMALL SQUARE
0x2614, # ☔ UMBRELLA WITH RAIN DROPS
0x2615, # ☕ HOT BEVERAGE
0x2648, # ♈ ARIES
0x2649, # ♉ TAURUS
0x264A, # ♊ GEMINI
0x264B, # ♋ CANCER
0x264C, # ♌ LEO
0x264D, # ♍ VIRGO
0x264E, # ♎ LIBRA
0x264F, # ♏ SCORPIUS
0x2650, # ♐ SAGITTARIUS
0x2651, # ♑ CAPRICORN
0x2652, # ♒ AQUARIUS
0x2653, # ♓ PISCES
0x267F, # ♿ WHEELCHAIR SYMBOL
0x2693, # ⚓ ANCHOR
0x26A1, # ⚡ HIGH VOLTAGE SIGN
0x26AA, # ⚪ MEDIUM WHITE CIRCLE
0x26AB, # ⚫ MEDIUM BLACK CIRCLE
0x26BD, # ⚽ SOCCER BALL
0x26BE, # ⚾ BASEBALL
0x26C4, # ⛄ SNOWMAN WITHOUT SNOW
0x26C5, # ⛅ SUN BEHIND CLOUD
0x26CE, # ⛎ OPHIUCHUS
0x26D4, # ⛔ NO ENTRY
0x26EA, # ⛪ CHURCH
0x26F2, # ⛲ FOUNTAIN
0x26F3, # ⛳ FLAG IN HOLE
0x26F5, # ⛵ SAILBOAT
0x26FA, # ⛺ TENT
0x26FD, # ⛽ FUEL PUMP
0x2705, # ✅ WHITE HEAVY CHECK MARK
0x270A, # ✊ RAISED FIST
0x270B, # ✋ RAISED HAND
0x2728, # ✨ SPARKLES
0x274C, # ❌ CROSS MARK
0x274E, # ❎ NEGATIVE SQUARED CROSS MARK
0x2753, # ❓ BLACK QUESTION MARK ORNAMENT
0x2754, # ❔ WHITE QUESTION MARK ORNAMENT
0x2755, # ❕ WHITE EXCLAMATION MARK ORNAMENT
0x2757, # ❗ HEAVY EXCLAMATION MARK SYMBOL
0x2795, # ➕ HEAVY PLUS SIGN
0x2796, # ➖ HEAVY MINUS SIGN
0x2797, # ➗ HEAVY DIVISION SIGN
0x27B0, # ➰ CURLY LOOP
0x27BF, # ➿ DOUBLE CURLY LOOP
0x2B1B, # ⬛ BLACK LARGE SQUARE
0x2B1C, # ⬜ WHITE LARGE SQUARE
0x2B50, # ⭐ WHITE MEDIUM STAR
0x2B55, # ⭕ HEAVY LARGE CIRCLE
}
# Characters we have decided we are doing as emoji-style in Android,
# despite UTR#51's recommendation
ANDROID_EMOJI = {
0x2600, # ☀ BLACK SUN WITH RAYS
0x2601, # ☁ CLOUD
0X260E, # ☎ BLACK TELEPHONE
0x261D, # ☝ WHITE UP POINTING INDEX
0x263A, # ☺ WHITE SMILING FACE
0x2660, # ♠ BLACK SPADE SUIT
0x2663, # ♣ BLACK CLUB SUIT
0x2665, # ♥ BLACK HEART SUIT
0x2666, # ♦ BLACK DIAMOND SUIT
0x270C, # ✌ VICTORY HAND
0x2744, # ❄ SNOWFLAKE
0x2764, # ❤ HEAVY BLACK HEART
}
def main(argv):
"""Subset the Noto Symbols font.
The first argument is the source file name, and the second argument is
the target file name.
"""
target_coverage = set()
# Add all characters in BLOCKS_TO_INCLUDE
for first, last, _ in unicode_data._parse_code_ranges(BLOCKS_TO_INCLUDE):
target_coverage.update(range(first, last+1))
# Add one-off characters
target_coverage |= ONE_OFF_ADDITIONS
# Remove characters preferably coming from Roboto
target_coverage -= LETTERLIKE_CHARS_IN_ROBOTO
# Remove characters that are supposed to default to emoji
target_coverage -= BMP_DEFAULT_EMOJI | ANDROID_EMOJI
# Remove dentistry symbols, as their main use appears to be for CJK:
# http://www.unicode.org/L2/L2000/00098-n2195.pdf
target_coverage -= set(range(0x23BE, 0x23CC+1))
# Remove COMBINING ENCLOSING KEYCAP. It's needed for Android's color emoji
# mechanism to work properly
target_coverage.remove(0x20E3)
source_file_name = argv[1]
target_file_name = argv[2]
subset.subset_font(
source_file_name,
target_file_name,
include=target_coverage)
if __name__ == '__main__':
main(sys.argv)