def decompositionBase(value): letterCategories = ("Ll", "Lu", "Lt", "Lo") try: c = unichr(value) # see not in category function except ValueError: return -1 decomposition = unicodedata.decomposition(c) if decomposition.startswith("<"): return -1 if " " not in decomposition: return -1 parts = decomposition.split(" ") unichrs = [unichr(int(i, 16)) for i in parts if i] letters = [ ord(i) for i in unichrs if unicodedata.category(i) in letterCategories ] letterCount = len(letters) if letterCount != 1: return -1 decomposedUniValue = letters[0] furtherDecomposedUniValue = decompositionBase(decomposedUniValue) if furtherDecomposedUniValue != -1: furtherFurtherDecomposedUniValue = decompositionBase( furtherDecomposedUniValue) if furtherFurtherDecomposedUniValue != -1: decomposedUniValue = furtherFurtherDecomposedUniValue else: decomposedUniValue = furtherDecomposedUniValue return decomposedUniValue
def input_from_name(self, name, seen=None, pad=False): """Given glyph name, return input to harbuzz to render this glyph. Returns input in the form of a (features, text) tuple, where `features` is a list of feature tags to activate and `text` is an input string. Argument `seen` is used by the method to avoid following cycles when recursively looking for possible input. `pad` can be used to add whitespace to text output, for non-spacing glyphs. Can return None in two situations: if no possible input is found (no simple unicode mapping or substitution rule exists to generate the glyph), or if the requested glyph already exists in `seen` (in which case this path of generating input should not be followed further). """ if name in self.memo: return self.memo[name] inputs = [] # avoid following cyclic paths through features if seen is None: seen = set() if name in seen: return None seen.add(name) # see if this glyph has a simple unicode mapping if name in self.reverse_cmap: text = unichr(self.reverse_cmap[name]) if text != unichr(0): inputs.append(((), text)) # check the substitution features inputs.extend(self._inputs_from_gsub(name, seen)) # seen.remove(name) # since this method sometimes returns None to avoid cycles, the # recursive calls that it makes might have themselves returned None, # but we should avoid returning None here if there are other options inputs = [i for i in inputs if i is not None] if not inputs: return None features, text = min(inputs) # can't pad if we don't support space if pad and self.space_width > 0: width, space = self.widths[name], self.space_width padding = ' ' * (width // space + (1 if width % space else 0)) text = padding + text self.memo[name] = features, text return self.memo[name]
def __init__(self, parentWindow): data = getExtensionDefault(self.identifier, dict()) self.w = Sheet((470, 580), parentWindow=parentWindow) self.w.tabs = Tabs((10, 10, -10, -40), ["TTF AutoHint", "HTML Preview"]) self.w.tabs[0].settings = self.settings = TTFAutoHintGroup((0, 0, -0, -0)) self.settings.set(data) y = 10 self.w.tabs[1].htmlText = TextBox((10, y, 100, 22), "HTML preview:") y += 30 self.w.tabs[1].html = self.html = CodeEditor((10, y, -10, 250), getExtensionDefault("%s.htmlPreview" % settingsIdentifier, htmlPreviewDefault), lexer="html") self.html.showLineNumbers(False) y += 260 self.w.tabs[1].globalCssText = TextBox((10, y, 100, 22), "CSS Style:") y += 30 self.w.tabs[1].globalCss = self.globalCss = CodeEditor((10, y, -10, -10), getExtensionDefault("%s.globalCSSPreview" % settingsIdentifier, ""), lexer="css") self.globalCss.showLineNumbers(False) self.w.saveButton = Button((-100, -30, -10, 20), "Save settings", callback=self.saveCallback, sizeStyle="small") self.w.setDefaultButton(self.w.saveButton) self.w.closeButton = Button((-190, -30, -110, 20), "Cancel", callback=self.closeCallback, sizeStyle="small") self.w.closeButton.bind(".", ["command"]) self.w.closeButton.bind(unichr(27), []) self.w.resetButton = Button((-280, -30, -200, 20), "Reset", callback=self.resetCallback, sizeStyle="small") self.w.open()
def __init__(self, parentWindow): data = getExtensionDefault(self.identifier, dict()) updateWithDefaultValues(data, defaultOptions) width = 380 height = 1000 self.w = Sheet((width, height), parentWindow=parentWindow) y = 10 self.w.threaded = CheckBox((10, y, -10, 22), "Threaded", value=data["threaded"]) y += 30 self.w.exportInFolders = CheckBox((10, y, -10, 22), "Export in Sub Folders", value=data["exportInFolders"]) y += 30 self.w.keepFileNames = CheckBox((10, y, -10, 22), "Keep file names (otherwise use familyName-styleName)", value=data["keepFileNames"]) y += 35 self.w.saveButton = Button((-100, y, -10, 20), "Save settings", callback=self.saveCallback, sizeStyle="small") self.w.setDefaultButton(self.w.saveButton) self.w.closeButton = Button((-190, y, -110, 20), "Cancel", callback=self.closeCallback, sizeStyle="small") self.w.closeButton.bind(".", ["command"]) self.w.closeButton.bind(unichr(27), []) self.w.resetButton = Button((-280, y, -200, 20), "Reset", callback=self.resetCallback, sizeStyle="small") y += 30 self.w.resize(width, y, False) self.w.open()
def getInputString(self, field, stripColon): """Read an input string from a field, and convert it to a list of glyphnames.""" inputString = field.get() pattern = re.compile(" *, *| +") if stripColon: i = inputString.find(":") if i != -1: inputString = inputString[i+1:] result1 = pattern.split(inputString) result2 = [] for c in result1: if len(c)>1: # glyph names if self.f is not None: if self.f.has_key(c): g = self.f[c] try: value = unicode(unichr(int(g.unicode))) result2.append(value) except TypeError: # unicode not set message ("word-o-mat: Glyph \"%s\" was found, but does not appear to have a Unicode value set. It can therefore not be processed, and will be skipped." % c) else: message ("word-o-mat: Conflict: Character \"%s\" was specified as required, but not found. It will be skipped." % c) else: message ("word-o-mat: Sorry, matching by glyph name is only supported when a font is open. Character \"%s\" will be skipped." % c) else: # character values result2.append(c) result = [unicode(s) for s in result2 if s] return result
def getInputString(self, field, stripColon): """Read an input string from a field, and convert it to a list of glyphnames.""" inputString = field.get() pattern = re.compile(" *, *| +") if stripColon: i = inputString.find(":") if i != -1: inputString = inputString[i + 1:] result1 = pattern.split(inputString) result2 = [] for c in result1: if len(c) > 1: # glyph names if self.f is not None: if self.f.has_key(c): g = self.f[c] try: value = unicode(unichr(int(g.unicode))) result2.append(value) except TypeError: # unicode not set message( "word-o-mat: Glyph \"%s\" was found, but does not appear to have a Unicode value set. It can therefore not be processed, and will be skipped." % c) else: message( "word-o-mat: Conflict: Character \"%s\" was specified as required, but not found. It will be skipped." % c) else: message( "word-o-mat: Sorry, matching by glyph name is only supported when a font is open. Character \"%s\" will be skipped." % c) else: # character values result2.append(c) result = [unicode(s) for s in result2 if s] return result
def __init__(self, parentWindow=None): self.needsUpdate = False self.__version__ = __version__ if not getDefault("DrawBotCheckForUpdatesAtStartup", True): return self.currentVersion = getCurrentVersion() self.needsUpdate = StrictVersion(__version__) < StrictVersion(self.currentVersion) if not self.needsUpdate: return if parentWindow: self.w = vanilla.Sheet((450, 130), parentWindow=parentWindow) else: self.w = vanilla.Window((450, 130)) self.w.appIcon = vanilla.ImageView((25, 15, 65, 65)) self.w.appIcon.setImage(imageObject=AppKit.NSApp().applicationIconImage()) title = "There is a new version of DrawBot!" txt = AppKit.NSAttributedString.alloc().initWithString_attributes_(title, {AppKit.NSFontAttributeName: AppKit.NSFont.boldSystemFontOfSize_(0)}) self.w.introBold = vanilla.TextBox((100, 15, -15, 20), txt) self.w.intro = vanilla.TextBox((100, 45, -15, 200), "DrawBot %s is out now (you have %s).\nWould you like to download it now?" % (self.currentVersion, __version__), sizeStyle="small") self.w.cancelButton = vanilla.Button((-270, -30, 60, 20), "Cancel", callback=self.cancelCallback, sizeStyle="small") self.w.cancelButton.bind(".", ["command"]) self.w.cancelButton.bind(unichr(27), []) self.w.openInBrowser = vanilla.Button((-200, -30, 120, 20), "Show In Browser", callback=self.openInBrowserCallback, sizeStyle="small") self.w.okButton = vanilla.Button((-70, -30, 55, 20), "OK", callback=self.okCallback, sizeStyle="small") self.w.setDefaultButton(self.w.okButton) self.w.open()
def font(indextable): font = TTFont() # ['a', 'b', 'c', ...] ch = 0x61 n = len(indextable.indices) font.glyphOrder = [unichr(i) for i in range(ch, ch+n)] font['TSI0'] = indextable return font
def font(indextable): font = TTFont() # ['a', 'b', 'c', ...] ch = 0x61 n = len(indextable.indices) font.glyphOrder = [unichr(i) for i in range(ch, ch + n)] font['TSI0'] = indextable return font
def unicodeInScripts(uv, scripts): """ Check UnicodeData's ScriptExtension property for unicode codepoint 'uv' and return True if it intersects with the set of 'scripts' provided, False if it does not intersect. Return None for 'Common' script ('Zyyy'). """ sx = unicodedata.script_extension(unichr(uv)) if "Zyyy" in sx: return None return not sx.isdisjoint(scripts)
def unicodeBidiType(uv): """Return "R" for characters with RTL direction, or "L" for LTR (whether 'strong' or 'weak'), or None for neutral direction. """ char = unichr(uv) bidiType = unicodedata.bidirectional(char) if bidiType in RTL_BIDI_TYPES: return "R" elif bidiType in LTR_BIDI_TYPES: return "L" else: return None
def to_upper(char): """Returns the upper case for a lower case character. This is not full upper casing, but simply reflects the 1-1 mapping in UnicodeData.txt.""" load_data() cp = _char_to_int(char) try: if _general_category_data[cp] == 'Ll': return unichr(_lower_to_upper_case[cp]) except KeyError: pass return char
def _load_unicode_data_txt(): """Load character data from UnicodeData.txt.""" global _defined_characters global _bidi_mirroring_characters if _defined_characters: return with open_unicode_data_file("UnicodeData.txt") as unicode_data_txt: unicode_data = _parse_semicolon_separated_data(unicode_data_txt.read()) for line in unicode_data: code = int(line[0], 16) char_name = line[1] general_category = line[2] combining_class = int(line[3]) decomposition = line[5] if decomposition.startswith('<'): # We only care about canonical decompositions decomposition = '' decomposition = decomposition.split() decomposition = [unichr(int(char, 16)) for char in decomposition] decomposition = ''.join(decomposition) bidi_mirroring = (line[9] == 'Y') if general_category == 'Ll': upcode = line[12] if upcode: upper_case = int(upcode, 16) _lower_to_upper_case[code] = upper_case if char_name.endswith("First>"): last_range_opener = code elif char_name.endswith("Last>"): # Ignore surrogates if "Surrogate" not in char_name: for char in xrange(last_range_opener, code + 1): _general_category_data[char] = general_category _combining_class_data[char] = combining_class if bidi_mirroring: _bidi_mirroring_characters.add(char) _defined_characters.add(char) else: _character_names_data[code] = char_name _general_category_data[code] = general_category _combining_class_data[code] = combining_class if bidi_mirroring: _bidi_mirroring_characters.add(code) _decomposition_data[code] = decomposition _defined_characters.add(code) _defined_characters = frozenset(_defined_characters) _bidi_mirroring_characters = frozenset(_bidi_mirroring_characters)
def _load_unicode_data_txt(): """Load character data from UnicodeData.txt.""" global _defined_characters global _bidi_mirroring_characters if _defined_characters: return with open_unicode_data_file("UnicodeData.txt") as unicode_data_txt: unicode_data = _parse_semicolon_separated_data(unicode_data_txt.read()) for line in unicode_data: code = int(line[0], 16) char_name = line[1] general_category = line[2] combining_class = int(line[3]) decomposition = line[5] if decomposition.startswith('<'): # We only care about canonical decompositions decomposition = '' decomposition = decomposition.split() decomposition = [unichr(int(char, 16)) for char in decomposition] decomposition = ''.join(decomposition) bidi_mirroring = (line[9] == 'Y') if general_category == 'Ll': upcode = line[12] if upcode: upper_case = int(upcode, 16) _lower_to_upper_case[code] = upper_case if char_name.endswith("First>"): last_range_opener = code elif char_name.endswith("Last>"): # Ignore surrogates if "Surrogate" not in char_name: for char in xrange(last_range_opener, code+1): _general_category_data[char] = general_category _combining_class_data[char] = combining_class if bidi_mirroring: _bidi_mirroring_characters.add(char) _defined_characters.add(char) else: _character_names_data[code] = char_name _general_category_data[code] = general_category _combining_class_data[code] = combining_class if bidi_mirroring: _bidi_mirroring_characters.add(code) _decomposition_data[code] = decomposition _defined_characters.add(code) _defined_characters = frozenset(_defined_characters) _bidi_mirroring_characters = frozenset(_bidi_mirroring_characters)
def _glyphIsRtl(self, name): """Return whether the closest-associated unicode character is RTL.""" delims = ('.', '_') uv = self.font[name].unicode while uv is None and any(d in name for d in delims): name = name[:max(name.rfind(d) for d in delims)] if name in self.font: uv = self.font[name].unicode if uv is None: return False return unicodedata.bidirectional(unichr(uv)) in ('R', 'AL')
def unicodeBidiType(uv): # return "R", "L", "N" (for numbers), or None for everything else char = unichr(uv) bidiType = unicodedata.bidirectional(char) if bidiType in STRONG_RTL_BIDI_TYPES: return "R" elif bidiType == STRONG_LTR_BIDI_TYPE: return "L" elif bidiType in LTR_NUMBER_BIDI_TYPES: return "N" else: return None
def input_from_name(self, name, seen=None, pad=False): """Given glyph name, return input to harbuzz to render this glyph. Returns input in the form of a (features, text) tuple, where `features` is a list of feature tags to activate and `text` is an input string. Argument `seen` is used by the method to avoid following cycles when recursively looking for possible input. `pad` can be used to add whitespace to text output, for non-spacing glyphs. Can return None in two situations: if no possible input is found (no simple unicode mapping or substitution rule exists to generate the glyph), or if the requested glyph already exists in `seen` (in which case this path of generating input should not be followed further). """ if name in self.memo: return self.memo[name] inputs = [] # avoid following cyclic paths through features if seen is None: seen = set() if name in seen: return None seen.add(name) # see if this glyph has a simple unicode mapping if name in self.reverse_cmap: text = unichr(self.reverse_cmap[name]) inputs.append(((), text)) # check the substitution features inputs.extend(self._inputs_from_gsub(name, seen)) seen.remove(name) # since this method sometimes returns None to avoid cycles, the # recursive calls that it makes might have themselves returned None, # but we should avoid returning None here if there are other options inputs = [i for i in inputs if i is not None] if not inputs: return None features, text = min(inputs) # can't pad if we don't support space if pad and self.space_width > 0: width, space = self.widths[name], self.space_width padding = ' ' * (width // space + (1 if width % space else 0)) text = padding + text self.memo[name] = features, text return self.memo[name]
def fontCharacters(self, font): """Check which Unicode characters are available in the font.""" if not font: return [] charset = [] gnames = [] for g in font: if g.unicode is not None: try: charset.append(unichr(int(g.unicode))) gnames.append(g.name) except ValueError: pass return charset, gnames
def __init__(self, parentWindow): data = getExtensionDefault(self.identifier, dict()) updateWithDefaultValues(data, defaultOptions) width = 380 height = 1000 self.w = Sheet((width, height), parentWindow=parentWindow) y = 10 self.w.threaded = CheckBox((10, y, -10, 22), "Threaded", value=data["threaded"]) y += 30 self.w.exportInFolders = CheckBox((10, y, -10, 22), "Export in Sub Folders", value=data["exportInFolders"]) y += 30 self.w.keepFileNames = CheckBox( (10, y, -10, 22), "Keep file names (otherwise use familyName-styleName)", value=data["keepFileNames"]) y += 35 self.w.saveButton = Button((-100, y, -10, 20), "Save settings", callback=self.saveCallback, sizeStyle="small") self.w.setDefaultButton(self.w.saveButton) self.w.closeButton = Button((-190, y, -110, 20), "Cancel", callback=self.closeCallback, sizeStyle="small") self.w.closeButton.bind(".", ["command"]) self.w.closeButton.bind(unichr(27), []) self.w.resetButton = Button((-280, y, -200, 20), "Reset", callback=self.resetCallback, sizeStyle="small") y += 30 self.w.resize(width, y, False) self.w.open()
def _get_unicode_category(unistr): # We use data for a fixed Unicode version (3.2) so that our generated # data files are independent of Python runtime that runs the rules. # By switching to current Unicode data, we could save some entries # in our exception tables, but the gains are not very large; only # about one thousand entries. if not unistr: return None if NARROW_PYTHON_BUILD: utf32_str = unistr.encode("utf-32-be") nchars = len(utf32_str) // 4 first_char = unichr(struct.unpack('>%dL' % nchars, utf32_str)[0]) else: first_char = unistr[0] return unicodedata.ucd_3_2_0.category(first_char)
def __init__(self, parentWindow): data = getExtensionDefault(self.identifier, dict()) self.w = Sheet((470, 580), parentWindow=parentWindow) self.w.tabs = Tabs((10, 10, -10, -40), ["TTF AutoHint", "HTML Preview"]) self.w.tabs[0].settings = self.settings = TTFAutoHintGroup( (0, 0, -0, -0)) self.settings.set(data) y = 10 self.w.tabs[1].htmlText = TextBox((10, y, 100, 22), "HTML preview:") y += 30 self.w.tabs[1].html = self.html = CodeEditor( (10, y, -10, 250), getExtensionDefault("%s.htmlPreview" % settingsIdentifier, htmlPreviewDefault), lexer="html") self.html.showLineNumbers(False) y += 260 self.w.tabs[1].globalCssText = TextBox((10, y, 100, 22), "CSS Style:") y += 30 self.w.tabs[1].globalCss = self.globalCss = CodeEditor( (10, y, -10, -10), getExtensionDefault("%s.globalCSSPreview" % settingsIdentifier, ""), lexer="css") self.globalCss.showLineNumbers(False) self.w.saveButton = Button((-100, -30, -10, 20), "Save settings", callback=self.saveCallback, sizeStyle="small") self.w.setDefaultButton(self.w.saveButton) self.w.closeButton = Button((-190, -30, -110, 20), "Cancel", callback=self.closeCallback, sizeStyle="small") self.w.closeButton.bind(".", ["command"]) self.w.closeButton.bind(unichr(27), []) self.w.resetButton = Button((-280, -30, -200, 20), "Reset", callback=self.resetCallback, sizeStyle="small") self.w.open()
def name(char, *args): """Returns the name of a character. Raises a ValueError exception if the character is undefined, unless an extra argument is given, in which case it will return that argument. """ if type(char) is int: char = unichr(char) # First try and get the name from unidata, which is faster and supports # CJK and Hangul automatic names try: return unicodedata.name(char) except ValueError as val_error: load_data() if ord(char) in _character_names_data: return _character_names_data[ord(char)] elif args: return args[0] else: raise Exception('no name for "%0x"' % ord(char))
def buildBaseWindow(self, parentWindow): """ Make the base window. """ self._dirty = False self._sheetWidth = 315 self._sheetHeight = 200 if parentWindow is None: self.w = vanilla.Window( (self._sheetWidth, self._sheetHeight), title=self._title, closable=False, miniaturizable=False, minSize=(self._sheetWidth, self._sheetHeight), textured=False) else: self.w = vanilla.Sheet( (self._sheetWidth, self._sheetHeight), parentWindow, minSize=(self._sheetWidth, self._sheetHeight), ) # cancel button self.w.cancelButton = vanilla.Button( (-205, -30, 100, 20), 'Cancel', callback=self.callbackCancelButton, sizeStyle='small') self.w.cancelButton.bind(".", ["command"]) self.w.cancelButton.bind(unichr(27), []) # ok button self.w.applyButton = vanilla.Button((-100, -30, -10, 20), 'Add Glyphs', callback=self.callbackApplyButton, sizeStyle='small') self.w.setDefaultButton(self.w.applyButton) # get the specialised stuff in self.fillSheet() self.setUpBaseWindowBehavior() #self.refresh() self.w.open()
def name(char, *args): """Returns the name of a character. Raises a ValueError exception if the character is undefined, unless an extra argument is given, in which case it will return that argument. """ if type(char) is int: char = unichr(char) # First try and get the name from unidata, which is faster and supports # CJK and Hangul automatic names try: return unicodedata.name(char) except ValueError as val_error: cp = ord(char) load_data() if cp in _character_names_data: return _character_names_data[cp] elif (cp,) in _emoji_sequence_data: return _emoji_sequence_data[(cp,)][0] elif args: return args[0] else: raise Exception('no name for "%0x"' % ord(char))
def __init__(self, parentWindow, callback=None): self.callback = callback self.w = vanilla.Sheet((350, 90), parentWindow=parentWindow) self.w.glyphNameText = vanilla.TextBox((10, 17, 100, 22), "Glyph Name:") self.w.glyphName = vanilla.EditText((100, 17, -10, 22)) self.w.addButton = vanilla.Button((-70, -30, -10, 20), "Add", callback=self.addCallback, sizeStyle="small") self.w.setDefaultButton(self.w.addButton) self.w.closeButton = vanilla.Button((-150, -30, -80, 20), "Cancel", callback=self.closeCallback, sizeStyle="small") self.w.closeButton.bind(".", ["command"]) self.w.closeButton.bind(unichr(27), []) self.w.open()
def buildBaseWindow(self, parentWindow): """ Make the base window. """ self._dirty = False self._sheetWidth = 400 self._sheetHeight = 500 if parentWindow is None: self.w = vanilla.Window((self._sheetWidth, self._sheetHeight), title = self._title, closable=False, miniaturizable=False, minSize=(self._sheetWidth, self._sheetHeight), textured=False) else: self.w = vanilla.Sheet((self._sheetWidth, self._sheetHeight), parentWindow, minSize=(self._sheetWidth, self._sheetHeight), ) # cancel button self.w.cancelButton = vanilla.Button((-205, -30, 100, 20), 'Cancel', callback=self.callbackCancelButton, sizeStyle='small') self.w.cancelButton.bind(".", ["command"]) self.w.cancelButton.bind(unichr(27), []) # ok button self.w.applyButton = vanilla.Button((-100, -30, -10, 20), 'Add Glyphs', callback=self.callbackApplyAddGlyphsToTargetFont, sizeStyle='small') self.w.setDefaultButton(self.w.applyButton) # get the specialised stuff in self.fillSheet() self.setUpBaseWindowBehavior() #self.refresh() self.w.open()
def category(value): c = unichr(value) return unicodedata.category(c)
def unicodeToChar(uni): import struct if uni < 0xFFFF: return unichr(uni) else: return struct.pack('i', uni).decode('utf-32')
'b': [('b.color1', 1), ('b.color2', 0)], 'c': [('c.color2', 1), ('c.color1', 0)]} def test_colr_cpal_raw(self, FontClass): testufo = FontClass(getpath("ColorTestRaw.ufo")) assert "com.github.googlei18n.ufo2ft.colorLayers" in testufo.lib assert "com.github.googlei18n.ufo2ft.colorPalettes" in testufo.lib result = compileTTF(testufo) palettes = [[(c.red, c.green, c.blue, c.alpha) for c in p] for p in result["CPAL"].palettes] assert palettes == [[(255, 76, 26, 255), (0, 102, 204, 255)]] layers = {gn: [(layer.name, layer.colorID) for layer in layers] for gn, layers in result["COLR"].ColorLayers.items()} assert layers == {"a": [('a.color1', 0), ('a.color2', 1)]} ASCII = [unichr(c) for c in range(0x20, 0x7E)] @pytest.mark.parametrize( "unicodes, expected", [ [ASCII + ["Þ"], {0}], # Latin 1 [ASCII + ["Ľ"], {1}], # Latin 2: Eastern Europe [ASCII + ["Ľ", "┤"], {1, 58}], # Latin 2 [["Б"], {2}], # Cyrillic [["Б", "Ѕ", "┤"], {2, 57}], # IBM Cyrillic [["Б", "╜", "┤"], {2, 49}], # MS-DOS Russian [["Ά"], {3}], # Greek [["Ά", "½", "┤"], {3, 48}], # IBM Greek [["Ά", "√", "┤"], {3, 60}], # Greek, former 437 G [ASCII + ["İ"], {4}], # Turkish
Fallback to *ascender + typoLineGap*. """ return info.ascender + getAttrWithFallback(info, "openTypeOS2TypoLineGap") def openTypeOS2WinDescentFallback(info): """ Fallback to *descender*. """ return abs(info.descender) # postscript _postscriptFontNameExceptions = set("[](){}<>/%") _postscriptFontNameAllowed = set([unichr(i) for i in range(33, 127)]) def normalizeStringForPostscript(s, allowSpaces=True): s = tounicode(s) normalized = [] for c in s: if c == " " and not allowSpaces: continue if c in _postscriptFontNameExceptions: continue if c not in _postscriptFontNameAllowed: # Use compatibility decomposed form, to keep parts in ascii c = unicodedata.normalize("NFKD", c) if not set(c) < _postscriptFontNameAllowed: c = tounicode(tobytes(c, errors="replace"))
def __init__(self): self.w = vanilla.FloatingWindow((310, 300), "Ramsay St. Settings", minSize=(310, 250), maxSize=(310, 700)) self.w.showPreview = vanilla.CheckBox( (10, 10, -10, 22), "Show Preview", value=RamsayStData.showPreview, callback=self.showPreviewCallback) self.w.fillColorText = vanilla.TextBox((10, 40, 110, 22), "Fill Color:") self.w.fillColor = vanilla.ColorWell((10, 60, 110, 40), color=RamsayStData.fillColor, callback=self.fillColorCallback) self.w.strokeColorText = vanilla.TextBox((130, 40, -10, 22), "Stroke Color:") self.w.strokeColor = vanilla.ColorWell( (130, 60, -10, 40), color=RamsayStData.strokeColor, callback=self.strokeColorCallback) items = RamsayStData.getItems() columnDescriptions = [ dict(title="Glyph Name", key="glyphName"), dict(title="Left", key="left"), dict(title="Right", key="right"), ] self.w.dataList = vanilla.List((10, 110, -10, -40), items, columnDescriptions=columnDescriptions, editCallback=self.dataListEditCallback) segmentDescriptions = [ dict(title="+"), dict(title="-"), dict(title="import"), dict(title="export") ] self.w.addDel = vanilla.SegmentedButton((12, -32, -140, 20), segmentDescriptions, selectionStyle="momentary", callback=self.addDelCallback) self.w.addDel.getNSSegmentedButton().setSegmentStyle_( NSSegmentStyleSmallSquare) self.w.okButton = vanilla.Button((-70, -30, -15, 20), "Apply", callback=self.okCallback, sizeStyle="small") self.w.setDefaultButton(self.w.okButton) self.w.closeButton = vanilla.Button((-140, -30, -80, 20), "Cancel", callback=self.closeCallback, sizeStyle="small") self.w.closeButton.bind(".", ["command"]) self.w.closeButton.bind(unichr(27), []) self.w.open()
def _dict_cmap_glyphs(cmap_glyphs): """[(ordinal, name)...] --> [{'char': uniXXXX, 'name': name}]""" mp = [] for uni, name in cmap_glyphs: mp.append({'char': unichr(uni), 'name': name}) return mp
def calcCodePageRanges(unicodes): """ Given a set of Unicode codepoints (integers), calculate the corresponding OS/2 CodePage range bits. This is a direct translation of FontForge implementation: https://github.com/fontforge/fontforge/blob/7b2c074/fontforge/tottf.c#L3158 """ codepageRanges = set() chars = [unichr(u) for u in unicodes] hasAscii = set(range(0x20, 0x7E)).issubset(unicodes) hasLineart = "┤" in chars for char in chars: if char == "Þ" and hasAscii: codepageRanges.add(0) # Latin 1 elif char == "Ľ" and hasAscii: codepageRanges.add(1) # Latin 2: Eastern Europe if hasLineart: codepageRanges.add(58) # Latin 2 elif char == "Б": codepageRanges.add(2) # Cyrillic if "Ѕ" in chars and hasLineart: codepageRanges.add(57) # IBM Cyrillic if "╜" in chars and hasLineart: codepageRanges.add(49) # MS-DOS Russian elif char == "Ά": codepageRanges.add(3) # Greek if hasLineart and "½" in chars: codepageRanges.add(48) # IBM Greek if hasLineart and "√" in chars: codepageRanges.add(60) # Greek, former 437 G elif char == "İ" and hasAscii: codepageRanges.add(4) # Turkish if hasLineart: codepageRanges.add(56) # IBM turkish elif char == "א": codepageRanges.add(5) # Hebrew if hasLineart and "√" in chars: codepageRanges.add(53) # Hebrew elif char == "ر": codepageRanges.add(6) # Arabic if "√" in chars: codepageRanges.add(51) # Arabic if hasLineart: codepageRanges.add(61) # Arabic; ASMO 708 elif char == "ŗ" and hasAscii: codepageRanges.add(7) # Windows Baltic if hasLineart: codepageRanges.add(59) # MS-DOS Baltic elif char == "₫" and hasAscii: codepageRanges.add(8) # Vietnamese elif char == "ๅ": codepageRanges.add(16) # Thai elif char == "エ": codepageRanges.add(17) # JIS/Japan elif char == "ㄅ": codepageRanges.add(18) # Chinese: Simplified chars elif char == "ㄱ": codepageRanges.add(19) # Korean wansung elif char == "央": codepageRanges.add(20) # Chinese: Traditional chars elif char == "곴": codepageRanges.add(21) # Korean Johab elif char == "♥" and hasAscii: codepageRanges.add(30) # OEM Character Set # TODO: Symbol bit has a special meaning (check the spec), we need # to confirm if this is wanted by default. # elif unichr(0xF000) <= char <= unichr(0xF0FF): # codepageRanges.add(31) # Symbol Character Set elif char == "þ" and hasAscii and hasLineart: codepageRanges.add(54) # MS-DOS Icelandic elif char == "╚" and hasAscii: codepageRanges.add(62) # WE/Latin 1 codepageRanges.add(63) # US elif hasAscii and hasLineart and "√" in chars: if char == "Å": codepageRanges.add(50) # MS-DOS Nordic elif char == "é": codepageRanges.add(52) # MS-DOS Canadian French elif char == "õ": codepageRanges.add(55) # MS-DOS Portuguese if hasAscii and "‰" in chars and "∑" in chars: codepageRanges.add(29) # Macintosh Character Set (US Roman) # when no codepage ranges can be enabled, fall back to enabling bit 0 # (Latin 1) so that the font works in MS Word: # https://github.com/googlei18n/fontmake/issues/468 if not codepageRanges: codepageRanges.add(0) return codepageRanges
def makeWords(self, sender=None): """Parse user input, save new values to prefs, compile and display the resulting words. I think this function is too long and bloated, it should be taken apart. ######## """ global warned self.f = CurrentFont() if self.f is not None: self.fontChars, self.glyphNames = self.fontCharacters(self.f) self.glyphNamesForValues = {self.fontChars[i]: self.glyphNames[i] for i in range(len(self.fontChars))} else: self.fontChars = [] self.glyphNames = [] self.wordCount = self.getIntegerValue(self.g1.wordCount) self.minLength = self.getIntegerValue(self.g1.minLength) self.maxLength = self.getIntegerValue(self.g1.maxLength) self.case = self.g1.case.get() self.customCharset = [] charset = self.g1.base.get() self.limitToCharset = True if charset == 0: self.limitToCharset = False elif charset == 2: # use selection if len(self.f.selection) == 0: # nothing selected message("word-o-mat: No glyphs were selected in the font window. Will use any characters available in the current font.") self.g1.base.set(1) # use font chars else: try: self.customCharset = [] for gname in self.f.selection: if self.f[gname].unicode is not None: try: self.customCharset.append(unichr(int(self.f[gname].unicode))) except ValueError: pass except AttributeError: pass elif charset == 3: # use mark color c = self.g1.colorWell.get() if c is None: pass elif c.className() == "NSCachedWhiteColor": # not set, corresponds to mark color set to None c = None self.customCharset = [] self.reqMarkColor = (c.redComponent(), c.greenComponent(), c.blueComponent(), c.alphaComponent()) if c is not None else None for g in self.f: if g.mark == self.reqMarkColor: try: self.customCharset.append(unichr(int(g.unicode))) except: pass if len(self.customCharset) == 0: message("word-o-mat: Found no glyphs that match the specified mark color. Will use any characters available in the current font.") self.g1.base.set(1) # use font chars self.toggleColorSwatch(0) self.matchMode = "text" if self.g2.matchMode.get() == 0 else "grep" # braucht es diese zeile noch? self.requiredLetters = self.getInputString(self.g2.textMode.mustLettersBox, False) self.requiredGroups[0] = self.getInputString(self.g2.textMode.group1box, True) self.requiredGroups[1] = self.getInputString(self.g2.textMode.group2box, True) self.requiredGroups[2] = self.getInputString(self.g2.textMode.group3box, True) self.matchPattern = self.g2.grepMode.grepBox.get() self.banRepetitions = self.g3.checkbox0.get() self.outputWords = [] # initialize/empty self.source = self.g1.source.get() languageCount = len(self.textfiles) if self.source == languageCount: # User Dictionary self.allWords = self.dictWords["user"] elif self.source == languageCount+1: # Use all languages for i in range(languageCount): # if any language: concatenate all the wordlists self.allWords.extend(self.dictWords[self.textfiles[i]]) elif self.source == languageCount+2: # Custom word list try: if self.customWords != []: self.allWords = self.customWords else: self.allWords = self.dictWords["ukacd"] self.g1.source.set(0) except AttributeError: self.allWords = self.dictWords["ukacd"] self.g1.source.set(0) else: # language lists for i in range(languageCount): if self.source == i: self.allWords = self.dictWords[self.textfiles[i]] # store new values as defaults markColorPref = self.reqMarkColor if self.reqMarkColor is not None else "None" extDefaults = { "wordCount": self.wordCount, "minLength": self.minLength, "maxLength": self.maxLength, "case": self.case, "limitToCharset": self.writeExtDefaultBoolean(self.limitToCharset), "source": self.source, "matchMode": self.matchMode, "matchPattern": self.matchPattern, # non compiled string "markColor": markColorPref, } for key, value in extDefaults.items(): setExtensionDefault("com.ninastoessinger.word-o-mat."+key, value) # go make words if self.checkInput(self.limitToCharset, self.fontChars, self.customCharset, self.requiredLetters, self.minLength, self.maxLength, self.case) == True: checker = wordcheck.wordChecker(self.limitToCharset, self.fontChars, self.customCharset, self.requiredLetters, self.requiredGroups, self.matchPatternRE, self.banRepetitions, self.minLength, self.maxLength, matchMode=self.matchMode) for i in self.allWords: if len(self.outputWords) >= self.wordCount: break else: w = choice(self.allWords) if self.case == 1: w = w.lower() elif self.case == 2: # special capitalization rules for Dutch IJ # this only works when Dutch is selected as language, not "any". try: ijs = ["ij", "IJ", "Ij"] if self.languageNames[self.source] == "Dutch" and w[:2] in ijs: wNew = "IJ" + w[2:] w = wNew else: w = w.title() except IndexError: w = w.title() elif self.case == 3: # special capitalization rules for German double s if u"ß" in w: w2 = w.replace(u"ß", "ss") w = w2 w = w.upper() if checker.checkWord(w, self.outputWords): self.outputWords.append(w) # output if len(self.outputWords) < 1: message("word-o-mat: no matching words found <sad trombone>") else: joinString = " " if self.g3.listOutput.get() == True: joinString = "\\n" self.outputWords = self.sortWordsByWidth(self.outputWords) outputString = joinString.join(self.outputWords) try: sp = OpenSpaceCenter(CurrentFont()) sp.setRaw(outputString) except: if warned == False: message("word-o-mat: No open fonts found; words will be displayed in the Output Window.") warned = True print("word-o-mat: %s" % outputString) else: print("word-o-mat: Aborted because of errors")
def unicodeScriptDirection(uv): sc = unicodedata.script(unichr(uv)) if sc in DFLT_SCRIPTS: return None return unicodedata.script_horizontal_direction(sc)
def _unescape_fn(m): if m.group(1): return unichr(int(m.group(1), 8)) return unichr(int(m.group(2), 16))
def block(value): char = unichr(value) return unicodedata.block(char)
def script(value): char = unichr(value) return unicodedata.script_name(unicodedata.script(char), default="Unknown")
def _unescape_fn(m): if m.group(1): return unichr(int(m.group(1)[1:], 8)) return unichr(int(m.group(2)[2:], 16))
""" font = info.getParent() if font is None: return abs(getAttrWithFallback(info, "descender")) bounds = getFontBounds(font) if bounds is None: return abs(getAttrWithFallback(info, "descender")) xMin, yMin, xMax, yMax = bounds if yMin > 0: return 0 return abs(yMin) # postscript _postscriptFontNameExceptions = set("[](){}<>/%") _postscriptFontNameAllowed = set([unichr(i) for i in range(33, 137)]) def normalizeStringForPostscript(s, allowSpaces=True): s = tounicode(s) normalized = [] for c in s: if c == " " and not allowSpaces: continue if c in _postscriptFontNameExceptions: continue if c not in _postscriptFontNameAllowed: c = unicodedata.normalize("NFKD", c) normalized.append(tostr(c)) return "".join(normalized) def normalizeNameForPostscript(name):