Initial commit

This commit is contained in:
2023-11-26 20:13:49 +01:00
commit dc2dc5c58b
820 changed files with 258269 additions and 0 deletions

View File

@ -0,0 +1,76 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
# All rights reserved.</center></h2>
#
# This software component is licensed by ST under Ultimate Liberty license
# SLA0044, the "License"; You may not use this file except in compliance with
# the License. You may obtain a copy of the License at:
# www.st.com/SLA0044
#
##############################################################################
require 'json'
class ApplicationFontProviderCpp < Template
def initialize(text_entries, typographies, output_directory, generate_font_format)
super(text_entries, typographies, output_directory)
@generate_font_format = generate_font_format
@cache = {}
end
def input_path
File.join(root_dir,'Templates','ApplicationFontProvider.cpp.temp')
end
def output_path
'src/ApplicationFontProvider.cpp'
end
def cache_file
File.join(@output_directory, 'cache/ApplicationFontProvider.cache')
end
def output_filename
File.join(@output_directory, output_path)
end
def run
@cache["typographies"] = typographies.collect{|t| [t.name, t.font_file, t.font_size, t.bpp] }
@cache["generate_font_format"] = @generate_font_format
new_cache_file = false
if not File::exists?(cache_file)
new_cache_file = true
else
#cache file exists, compare data with cache file
old_cache = JSON.parse(File.read(cache_file))
new_cache_file = (old_cache != @cache)
end
if new_cache_file
#write new cache file
FileIO.write_file_silent(cache_file, @cache.to_json)
end
if (!File::exists?(output_filename)) || new_cache_file
#generate ApplicationFontProvider.cpp
super
end
end
def font_index(index)
#map typographies to index of first using same font = font index
@font_index ||=
begin
list = {}
typographies.each_with_index do |typography, index|
name = "#{typography.cpp_name}_#{typography.font_size}_#{typography.bpp}bpp"
if not list[name]
list[name] = list.size
end
end
list
end
typography = typographies[index]
name = "#{typography.cpp_name}_#{typography.font_size}_#{typography.bpp}bpp"
@font_index[name]
end
def save_flashreader
@generate_font_format == "1"
end
end

View File

@ -0,0 +1,93 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
# All rights reserved.</center></h2>
#
# This software component is licensed by ST under Ultimate Liberty license
# SLA0044, the "License"; You may not use this file except in compliance with
# the License. You may obtain a copy of the License at:
# www.st.com/SLA0044
#
##############################################################################
class ApplicationFontProviderHpp < Template
def initialize(text_entries, typographies, output_directory, generate_font_format)
super(text_entries, typographies, output_directory)
@generate_font_format = generate_font_format
@cache = {}
end
def input_path
File.join(root_dir,'Templates','ApplicationFontProvider.hpp.temp')
end
def output_path
'/include/fonts/ApplicationFontProvider.hpp'
end
def cache_file
File.join(@output_directory, 'cache/ApplicationFontProviderHpp.cache')
end
def output_filename
File.join(@output_directory, output_path)
end
def run
@cache["typographies"] = typographies.collect{|t| [t.name, t.font_file, t.font_size, t.bpp] }
@cache["generate_font_format"] = @generate_font_format
@max_length = 0
typographies.each do |t|
if t.name.length > @max_length
@max_length = t.name.length
end
end
new_cache_file = false
if not File::exists?(cache_file)
new_cache_file = true
else
#cache file exists, compare data with cache file
old_cache = JSON.parse(File.read(cache_file))
new_cache_file = (old_cache != @cache)
end
if new_cache_file
#write new cache file
FileIO.write_file_silent(cache_file, @cache.to_json)
end
if (!File::exists?(output_filename)) || new_cache_file
#generate ApplicationFontProvider.hpp
super
end
end
def font_index(index)
#map typographies to index of first using same font = font index
@font_index ||=
begin
list = {}
typographies.each_with_index do |typography, index|
name = "#{typography.cpp_name}_#{typography.font_size}_#{typography.bpp}bpp"
if not list[name]
list[name] = list.size
end
end
list
end
typography = typographies[index]
name = "#{typography.cpp_name}_#{typography.font_size}_#{typography.bpp}bpp"
@font_index[name]
end
def max_font_index
if @font_index
@font_index.size
else
0
end
end
def font_comment(index)
typography = typographies[index]
spaces = @max_length - typography.name.length
"#{' '*spaces}// #{typography.cpp_name}_#{typography.font_size}_#{typography.bpp}bpp"
end
def save_flashreader
@generate_font_format == "1"
end
end

View File

@ -0,0 +1,30 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
# All rights reserved.</center></h2>
#
# This software component is licensed by ST under Ultimate Liberty license
# SLA0044, the "License"; You may not use this file except in compliance with
# the License. You may obtain a copy of the License at:
# www.st.com/SLA0044
#
##############################################################################
class CachedFontCpp < Template
def input_path
File.join(root_dir,'Templates','CachedFont.cpp.temp')
end
def output_path
'/src/CachedFont.cpp'
end
def output_filename
File.join(@output_directory, output_path)
end
def run
if (!File::exists?(output_filename))
#generate CachedFont.cpp
super
end
end
end

View File

@ -0,0 +1,30 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
# All rights reserved.</center></h2>
#
# This software component is licensed by ST under Ultimate Liberty license
# SLA0044, the "License"; You may not use this file except in compliance with
# the License. You may obtain a copy of the License at:
# www.st.com/SLA0044
#
##############################################################################
class CachedFontHpp < Template
def input_path
File.join(root_dir,'Templates','CachedFont.hpp.temp')
end
def output_path
'/include/fonts/CachedFont.hpp'
end
def output_filename
File.join(@output_directory, output_path)
end
def run
if (!File::exists?(output_filename))
#generate CachedFont.hpp
super
end
end
end

View File

@ -0,0 +1,30 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
# All rights reserved.</center></h2>
#
# This software component is licensed by ST under Ultimate Liberty license
# SLA0044, the "License"; You may not use this file except in compliance with
# the License. You may obtain a copy of the License at:
# www.st.com/SLA0044
#
##############################################################################
class FontCacheCpp < Template
def input_path
File.join(root_dir,'Templates','FontCache.cpp.temp')
end
def output_path
'/src/FontCache.cpp'
end
def output_filename
File.join(@output_directory, output_path)
end
def run
if (!File::exists?(output_filename))
#generate FontCache.cpp
super
end
end
end

View File

@ -0,0 +1,30 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
# All rights reserved.</center></h2>
#
# This software component is licensed by ST under Ultimate Liberty license
# SLA0044, the "License"; You may not use this file except in compliance with
# the License. You may obtain a copy of the License at:
# www.st.com/SLA0044
#
##############################################################################
class FontCacheHpp < Template
def input_path
File.join(root_dir,'Templates','FontCache.hpp.temp')
end
def output_path
'/include/fonts/FontCache.hpp'
end
def output_filename
File.join(@output_directory, output_path)
end
def run
if (!File::exists?(output_filename))
#generate FontCache.hpp
super
end
end
end

View File

@ -0,0 +1,122 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
# All rights reserved.</center></h2>
#
# This software component is licensed by ST under Ultimate Liberty license
# SLA0044, the "License"; You may not use this file except in compliance with
# the License. You may obtain a copy of the License at:
# www.st.com/SLA0044
#
##############################################################################
class FontsCpp
def self.font_convert=(font_convert)
@@font_convert = font_convert
end
def initialize(text_entries, typographies, output_directory, font_asset_path, data_format, generate_binary_fonts, generate_font_format)
@typographies = typographies
@output_directory = output_directory
@font_asset_path = font_asset_path
@data_format = data_format
@generate_binary_fonts = generate_binary_fonts
@generate_font_format = generate_font_format
end
def run
unique_typographies = @typographies.map{ |t| Typography.new("", t.font_file, t.font_size, t.bpp, t.fallback_character, t.ellipsis_character) }.uniq
#remove old Table, Kerning, Font files
#1. Create a list of font names
font_names = unique_typographies.collect do |typography|
"#{typography.cpp_name}_#{typography.font_size}_#{typography.bpp}bpp"
end
local_path = "#{@output_directory}/src".gsub('\\','/')
#2, scan for Kerning files, delete files not using a font in font_names
Dir["#{local_path}/Kerning_*.cpp"].each do |kerning_file|
if font_names.none? {|font_name| kerning_file == "#{local_path}/Kerning_#{font_name}.cpp" }
FileUtils.rm(kerning_file)
end
end
#3, scan for Table files
Dir["#{local_path}/Table_*.cpp"].each do |table_file|
if font_names.none? {|font_name| table_file == "#{local_path}/Table_#{font_name}.cpp" }
FileUtils.rm(table_file)
end
end
#4, scan for Font files, remove unused
Dir["#{local_path}/Font_*.cpp"].each do |font_file|
if font_names.none? {|font_name| font_file.match /#{local_path}\/Font_#{font_name}_\d+.cpp/ }
FileUtils.rm(font_file)
end
end
#5, scan for cache files
local_path = "#{@output_directory}/cache".gsub('\\','/')
Dir["#{local_path}/Font_*Cpp.cache"].each do |cache_file|
if font_names.none? {|font_name| cache_file == "#{local_path}/Font_#{font_name}Cpp.cache" }
FileUtils.rm(cache_file)
end
end
unique_typographies.sort_by { |t| sprintf("%s %04d %d",t.font_file,t.font_size,t.bpp) }.each do |typography|
fonts_directory = File.expand_path(@output_directory)
font_file = File.expand_path("#{@font_asset_path}/#{typography.font_file}")
font_index = fontmap["getFont_#{typography.cpp_name}_#{typography.font_size}_#{typography.bpp}bpp"]
fallback_char = typography[:fallback_character]
fallback_char ||= 0
ellipsis_char = typography[:ellipsis_character]
ellipsis_char ||= 0
byte_align = @data_format.match("A#{typography.bpp}") ? "-ba" : ""
cmd = "\"#{@@font_convert}\" \
-f \"#{font_file}\" \
-i #{font_index} \
-w #{typography.font_size} \
-r #{typography.font_size} \
-o \"#{fonts_directory}\" \
-c \"#{@output_directory}/UnicodeList#{typography.cpp_name}_#{typography.font_size}_#{typography.bpp}.txt\" \
-n \"#{typography.cpp_name}\" \
-b #{typography.bpp} \
-d #{fallback_char} \
-e #{ellipsis_char} \
-bf #{@generate_binary_fonts} \
-ff #{@generate_font_format} \
#{byte_align}"
#puts "Command: #{cmd}"
output = `#{cmd}`
#puts "FontConverter: #{output}\n"
if !$?.success?
puts cmd
puts output
raise "Error generating font from #{font_file}"
elsif output.match(/WARNING/i)
puts output
end
end
end
def fonts
@fonts ||=
begin
@typographies.map{ |t| Typography.new("", t.font_file, t.font_size, t.bpp) }.uniq.collect do |f|
"getFont_#{f.cpp_name}_#{f.font_size}_#{f.bpp}bpp"
end
end
end
def fontmap
@fontmap ||=
begin
@fontmap = Hash.new
fonts.each_with_index do |f, i|
fontmap[f] = i
end
fontmap
end
end
end

View File

@ -0,0 +1,30 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
# All rights reserved.</center></h2>
#
# This software component is licensed by ST under Ultimate Liberty license
# SLA0044, the "License"; You may not use this file except in compliance with
# the License. You may obtain a copy of the License at:
# www.st.com/SLA0044
#
##############################################################################
class GeneratedFontCpp < Template
def input_path
File.join(root_dir,'Templates','GeneratedFont.cpp.temp')
end
def output_path
'/src/GeneratedFont.cpp'
end
def output_filename
File.join(@output_directory, output_path)
end
def run
if (!File::exists?(output_filename))
#generate GeneratedFont.cpp
super
end
end
end

View File

@ -0,0 +1,30 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
# All rights reserved.</center></h2>
#
# This software component is licensed by ST under Ultimate Liberty license
# SLA0044, the "License"; You may not use this file except in compliance with
# the License. You may obtain a copy of the License at:
# www.st.com/SLA0044
#
##############################################################################
class GeneratedFontHpp < Template
def input_path
File.join(root_dir,'Templates','GeneratedFont.hpp.temp')
end
def output_path
'/include/fonts/GeneratedFont.hpp'
end
def output_filename
File.join(@output_directory, output_path)
end
def run
if (!File::exists?(output_filename))
#generate GeneratedFont.hpp
super
end
end
end

View File

@ -0,0 +1,282 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
# All rights reserved.</center></h2>
#
# This software component is licensed by ST under Ultimate Liberty license
# SLA0044, the "License"; You may not use this file except in compliance with
# the License. You may obtain a copy of the License at:
# www.st.com/SLA0044
#
##############################################################################
require 'json'
class LanguagesBin
def initialize(text_entries, typographies, output_directory)
@text_entries = text_entries
@typographies = typographies
@output_directory = output_directory
end
def run
#remove_old_binary_files
@text_entries.languages.each do |language|
LanguageXxBin.new(@text_entries, @typographies, @output_directory, language).run
end
end
private
def remove_old_binary_files
# Remove any old bin file
local_path = @output_directory.gsub('\\','/')
Dir["#{local_path}/binary/Language*.bin"].each do |language_bin_file|
puts "Deleting #{language_bin_file}"
FileUtils.rm(language_bin_file)
end
end
end
class LanguageXxBin < Template
Presenter = Struct.new(:text_id, :unicodes)
LanguageHeader = Struct.new(:offset_to_texts, :offset_to_indices, :offset_to_typedtext)
TypedTextPresenter = Struct.new(:alignment, :direction, :typography)
ALIGNMENT = { "LEFT" => 0, "CENTER" => 1, "RIGHT" => 2 }
TEXT_DIRECTION = { "LTR" => 0, "RTL" => 1 }
def initialize(text_entries, typographies, output_directory, language)
@language = language
@typographies = typographies
@text_entries = text_entries
@output_directory = output_directory
@cache = {}
end
def cache_file
File.join(@output_directory, "cache/LanguageBin_#{@language}.cache")
end
def alignment_to_value(alignment)
ALIGNMENT[alignment.to_s]
end
def text_direction_to_value(direction)
TEXT_DIRECTION[direction.to_s]
end
def language
@language
end
def entries
#only generate entries once
@cached_entries ||=
begin
entries = text_entries
entries = handle_no_entries(entries, "DO_NOT_USE")
present(entries)
end
end
def entries_texts_const_initialization
entries.map { |entry| " #{entry.text_id}_#{language}" }.join(",\n")
end
def input_path
File.join(@output_directory, output_path)
end
def output_path
"binary/Language#{language}.bin"
end
def typed_texts(language)
text_entries.collect do |entry|
typography_name = entry.typographies[language] || entry.typography
typography = typographies.find { |t| t.name == typography_name }
alignment = entry.alignments[language] || entry.alignment
direction = entry.directions[language] || entry.direction
TypedTextPresenter.new(alignment, direction, typography);
end
end
def typed_texts_(language)
typed_text_str = typed_texts(language)
puts "typed_text_str = #{typed_text_str}"
end
def fonts
typographies.map{ |t| Typography.new("", t.font_file, t.font_size, t.bpp) }.uniq.collect do |f|
"getFont_#{f.cpp_name}_#{f.font_size}_#{f.bpp}bpp"
end
end
def fontmap
fontmap = Hash.new
fonts.each_with_index do |f, i|
fontmap[f] = i
end
fontmap
end
def header(entries)
nb_entries = 0
header_struct_size = 12
header_unicodes_size = 0;
offset_to_texts = 0
offset_to_indices = 0
offset_to_typedtext = 0
entries.each do |entry|
nb_entries += 1
entry.unicodes.split(', ').each { |c|
header_unicodes_size += 2
}
end
offset_to_texts = header_struct_size
offset_to_indices = ((offset_to_texts + header_unicodes_size + 3) &~ 0x3)
offset_to_typedtext = ((offset_to_indices + (4 * nb_entries) + 3) &~ 0x3)
# puts "Number of Entries = #{nb_entries}"
# puts "Header size = #{header_struct_size}"
# puts "Unicodes size = #{header_unicodes_size}"
# puts "Text Offset = #{offset_to_texts}"
# puts "Indices Offset = #{offset_to_indices}"
# puts "TypedText Offset = #{offset_to_typedtext}"
LanguageHeader.new('0x' + offset_to_texts.to_s(16), '0x' + offset_to_indices.to_s(16), '0x' + offset_to_typedtext.to_s(16))
end
def output_filename
File.join(@output_directory, output_path)
end
def run
#build cache dictionary
@cache["typographies"] = typographies.collect{|t| [t.name, t.font_file, t.font_size, t.bpp] }
@cache["language"] = @language
@cache["language_index"] = @text_entries.languages.index(@language)
list = [] #list of index,textid
entries.each_with_index do |entry, index|
list[index] = [entry.unicodes, entry.text_id]
end
@cache["indices"] = list
new_cache_file = false
if not File::exists?(cache_file)
new_cache_file = true
else
#cache file exists, compare data with cache file
old_cache = JSON.parse(File.read(cache_file))
new_cache_file = (old_cache != @cache)
end
if new_cache_file
#write new cache file
FileIO.write_file_silent(cache_file, @cache.to_json)
end
if (!File::exists?(output_filename)) || new_cache_file
#generate LanguageXX.bin
FileUtils.mkdir_p(File.dirname(input_path))
callingPath = Pathname.new($calling_path)
filePath = Pathname.new(input_path)
puts "Generating #{filePath.relative_path_from(callingPath)}"
File.open(input_path,'wb') do |f|
# create indices array
indices_arr = []
# Writing Language Header
lang_header = header(entries)
lang_header.each { |c|
f.write [c.to_i(16)].pack("L")
}
# Writing Texts data
indices_arr.clear
indices_arr << 0 # first element is @ offset zero
nb_data_in_entry = 0
entries.each do |entry|
#puts "All Unicodes #{entry.unicodes}"
entry.unicodes.split(', ').each { |c|
f.write [c.to_i(16)].pack("S")
nb_data_in_entry += 1
}
indices_arr << nb_data_in_entry #populate the indices array
end
# Add padding to align on word size for next indeces data writing
loop do
if Integer(f.pos) == Integer(lang_header.offset_to_indices)
break
end
f.write ["0x00".to_i(16)].pack("S")
end
# Remove last indice
indices_arr.pop
# Writing Indices
indices_arr.each { |idx| f.write [idx].pack("L") }
# Add padding to align on word size for next typed_text data writing
loop do
if Integer(f.pos) == Integer(lang_header.offset_to_typedtext)
break
end
f.write ["0x00".to_i(16)].pack("S")
end
# Create and Fill TypedTextsData Array
typed_text_arr = []
if typed_texts(language).empty?
# puts " { #{0}, #{alignment_to_value("LEFT")}, #{text_direction_to_value("LTR")} }"
typed_text_arr << 0 << alignment_to_value("LEFT") << text_direction_to_value("LTR")
else
typed_texts(language).map do |typed_text|
fontIdx = fontmap["getFont_#{typed_text.typography.cpp_name}_#{typed_text.typography.font_size}_#{typed_text.typography.bpp}bpp"]
alignment = alignment_to_value(typed_text.alignment.upcase)
direction = text_direction_to_value(typed_text.direction.upcase)
# puts "Font Index --> #{fontIdx}"
# puts "Alignment --> #{typed_text.alignment.upcase}"
# puts "Text Direction --> #{typed_text.direction.upcase}"
# puts " { #{fontIdx}, #{alignment_to_value(typed_text.alignment.upcase)}, #{text_direction_to_value(typed_text.direction.upcase)} }"
combined = direction.to_s(2).to_i(2) * 4 + alignment.to_s(2).to_i(2)
typed_text_arr << fontIdx << combined
end
end
# Writing TypedTextsData
typed_text_arr.each do |idx|
f.write [idx].pack("C")
end
# # Add padding to align the binary file size on word size
loop do
if ((f.pos & 0x3) == 0)
break
end
f.write ["0x00".to_i(16)].pack("C")
end
end
end
end
private
def handle_no_entries(entries, text)
if entries.empty?
empty_entry = TextEntry.new(text, "typography")
empty_entry.add_translation(language, "")
[empty_entry]
else
entries
end
end
def present(entries)
entries.map do |entry|
Presenter.new(entry.cpp_text_id, ( entry.translation_in(language).unicodes.map { |u| '0x' + u.to_s(16) } << '0x0' ) .join(', ') )
end
end
end

View File

@ -0,0 +1,179 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
# All rights reserved.</center></h2>
#
# This software component is licensed by ST under Ultimate Liberty license
# SLA0044, the "License"; You may not use this file except in compliance with
# the License. You may obtain a copy of the License at:
# www.st.com/SLA0044
#
##############################################################################
require 'json'
class LanguagesCpp
def initialize(string_indices, text_entries, output_directory, remap_identical_texts, generate_binary_translations)
@string_indices = string_indices #dictionary of all string indices into the characters array
@text_entries = text_entries
@output_directory = output_directory
@remap_identical_texts = remap_identical_texts
@generate_binary_translations = generate_binary_translations
end
def run
@text_entries.languages.each do |language|
LanguageXxCpp.new(@string_indices, @text_entries, @output_directory, @remap_identical_texts, @generate_binary_translations, language).run
end
#remove any unused LanguageXX.cpp files
Dir.glob("#{@output_directory}/src/Language*.cpp").each do |file|
m = /Language(.*).cpp/.match(file)
if !@text_entries.languages.include?(m[1])
File.delete(file) if File.exist?(file)
end
end
end
end
class LanguageXxCpp < Template
Presenter = Struct.new(:text_id, :int_array)
def initialize(string_indices, text_entries, output_directory, remap_identical_texts, generate_binary_translations, language)
@string_indices = string_indices #dictionary of all string indices into the characters array
@remap_identical_texts = remap_identical_texts
@generate_binary_translations = generate_binary_translations
@language = language
super(text_entries, [], output_directory)
@cache = {}
end
def cache_file
File.join(@output_directory, "cache/LanguageCpp_#{@language}.cache")
end
def output_filename
File.join(@output_directory, output_path)
end
def texts
@text_entries.entries.map(&:cpp_text_id)
end
def run
#build cache dictionary
@cache["remap"] = @remap_identical_texts
@cache["language"] = @language
@cache["language_index"] = @text_entries.languages.index(@language)
if remap_strings?
#save text ids and index
list = [] #list of index,textid
entries.each_with_index do |entry, index|
list[index] = [string_index(entry), entry.text_id]
end
@cache["indices"] = list
else
#save texts
texts = []
entries.each_with_index do |entry, index|
texts << [entry.text_id, entry.int_array]
end
@cache["texts"] = texts
end
new_cache_file = false
if not File::exists?(cache_file)
new_cache_file = true
else
#cache file exists, compare data with cache file
old_cache = JSON.parse(File.read(cache_file))
new_cache_file = (old_cache != @cache)
end
if new_cache_file
#write new cache file
FileIO.write_file_silent(cache_file, @cache.to_json)
end
if (!File::exists?(output_filename)) || new_cache_file
#generate LanguageXX.cpp
super
end
end
def remap_strings?
@remap_identical_texts=="yes"
end
def generate_binary_files?
@generate_binary_translations=="yes"
end
def language
@language
end
def entries
#only generate entries once
@cached_entries ||=
begin
entries = text_entries
entries = handle_no_entries(entries, "DO_NOT_USE")
present(entries)
end
end
def entries_texts_const_initialization
entries.map { |entry| " #{entry.text_id}_#{language}" }.join(",\n")
end
def string_index(entry)
index = @string_indices[entry.int_array]
index.to_s
end
# def entries_s
# entries = text_entries.entries_with_1_substitution
# entries = handle_no_entries(entries, "DO_NOT_USE_S")
# present(entries)
# end
# def entries_s_texts_const_initialization
# entries_s.map { |entry| "#{entry.text_id}_#{language}" }.join(",\n")
# end
# def entries_ss
# entries = text_entries.entries_with_2_substitutions
# entries = handle_no_entries(entries, "DO_NOT_USE_SS")
# present(entries)
# end
# def entries_ss_texts_const_initialization
# entries_ss.map { |entry| "#{entry.text_id}_#{language}" }.join(",\n")
# end
def input_path
File.join(root_dir,'Templates','LanguageXX.cpp.temp')
end
def output_path
"src/Language#{language}.cpp"
end
private
def handle_no_entries(entries, text)
if entries.empty?
empty_entry = TextEntry.new(text, "typography")
empty_entry.add_translation(language, "")
[empty_entry]
else
entries
end
end
def present(entries)
entries.map do |entry|
Presenter.new(entry.cpp_text_id, entry.translation_in(language).unicodes)
end
end
end

View File

@ -0,0 +1,34 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
# All rights reserved.</center></h2>
#
# This software component is licensed by ST under Ultimate Liberty license
# SLA0044, the "License"; You may not use this file except in compliance with
# the License. You may obtain a copy of the License at:
# www.st.com/SLA0044
#
##############################################################################
require 'erb'
require 'lib/file_io'
class Template
attr_accessor :text_entries
attr_accessor :typographies
def initialize(text_entries, typographies, output_directory)
@text_entries = text_entries
@typographies = typographies
@output_directory = output_directory
end
def run
result = ERB.new(File.read(input_path).
gsub(WINDOWS_LINE_ENDINGS, UNIX_LINE_ENDINGS),0,"<>").result( binding ).
gsub(WINDOWS_LINE_ENDINGS, UNIX_LINE_ENDINGS).
gsub(UNIX_LINE_ENDINGS, LINE_ENDINGS)
FileIO.write_file(File.join(@output_directory, output_path), result)
end
end

View File

@ -0,0 +1,62 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
# All rights reserved.</center></h2>
#
# This software component is licensed by ST under Ultimate Liberty license
# SLA0044, the "License"; You may not use this file except in compliance with
# the License. You may obtain a copy of the License at:
# www.st.com/SLA0044
#
##############################################################################
require 'json'
class TextKeysAndLanguages < Template
def initialize(text_entries, typographies, output_directory)
super
@cache = {}
end
def countries
text_entries.languages.map { |language| language.upcase }.join(",\n ")
end
def texts
text_entries.entries.map(&:cpp_text_id)
end
def input_path
File.join(root_dir,'Templates','TextKeysAndLanguages.hpp.temp')
end
def output_path
'include/texts/TextKeysAndLanguages.hpp'
end
def cache_file
File.join(@output_directory, 'cache/TextKeysAndLanguages.cache')
end
def output_filename
File.join(@output_directory, output_path)
end
def run
@cache["languages"] = text_entries.languages
@cache["textids"] = texts;
new_cache_file = false
if not File::exists?(cache_file)
new_cache_file = true
else
#cache file exists, compare data with cache file
old_cache = JSON.parse(File.read(cache_file))
new_cache_file = (old_cache != @cache)
end
if new_cache_file
#write new cache file
FileIO.write_file_silent(cache_file, @cache.to_json)
end
if (!File::exists?(output_filename)) || new_cache_file || $Force_Generate_TextKeysAndLanguages
#generate TextKeysAndLanguages.hpp
super
end
end
end

View File

@ -0,0 +1,115 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
# All rights reserved.</center></h2>
#
# This software component is licensed by ST under Ultimate Liberty license
# SLA0044, the "License"; You may not use this file except in compliance with
# the License. You may obtain a copy of the License at:
# www.st.com/SLA0044
#
##############################################################################
class TextsCpp < Template
def initialize(characters, text_entries, typographies, output_directory, remap_identical_texts, generate_binary_translations)
@characters = characters #one array of the needed strings in optimal order
@remap_identical_texts = remap_identical_texts
@generate_binary_translations = generate_binary_translations
super(text_entries, typographies, output_directory)
@cache = {}
end
def run
#build @cache and compare with file if exists
@cache["remap"] = @remap_identical_texts
if remap_strings?
#record language list and strings
@cache["languages"] = countries
@cache["characters"] = @characters
else
#record list of languages only
@cache["languages"] = countries
end
new_cache_file = false
if not File::exists?(cache_file)
new_cache_file = true
else
#cache file exists, compare data with cache file
old_cache = JSON.parse(File.read(cache_file))
new_cache_file = (old_cache != @cache)
end
if new_cache_file
#write new cache file
FileIO.write_file_silent(cache_file, @cache.to_json)
end
if (!File::exists?(output_filename)) || new_cache_file
#generate TypedTextDatabase.cpp
super
end
end
def remap_strings?
@remap_identical_texts=="yes"
end
def generate_binary_files?
@generate_binary_translations=="yes"
end
def countries
text_entries.languages.map { |language| language.capitalize }
end
def countries_texts
if countries.empty?
"0"
else
countries.map{ |country| "texts#{country}" }.join(",\n ")
end
end
def is_rtl
text_entries.is_rtl
end
def input_path
File.join(root_dir,'Templates','Texts.cpp.temp')
end
def output_path
'src/Texts.cpp'
end
def cache_file
File.join(@output_directory, 'cache/TextsCpp.cache')
end
def output_filename
File.join(@output_directory, output_path)
end
def all_unicodes
if @characters.length==0
return "0 // No characters in application"
end
text = ""
offset = 0
initial_offset = 0
@characters.inject("") do |txt, i|
last = (offset == @characters.length-1)
txt << "0x#{i.to_s(16)}#{last ? '' : ','} "
offset+=1
if i==0 #end of current word, change line
txt << "// @#{initial_offset} \"#{text}\""
txt << "\n " unless last
text = ""
initial_offset = offset
else
if i==2
text << "<>"
elsif i>=32 && i <127
text << i.chr
else
text << '?'
end
end
txt
end
end
end

View File

@ -0,0 +1,139 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
# All rights reserved.</center></h2>
#
# This software component is licensed by ST under Ultimate Liberty license
# SLA0044, the "License"; You may not use this file except in compliance with
# the License. You may obtain a copy of the License at:
# www.st.com/SLA0044
#
##############################################################################
class TypedTextDatabaseCpp < Template
TypedTextPresenter = Struct.new(:alignment, :direction, :typography)
def initialize(text_entries, typographies, output_directory, generate_binary_translations, generate_font_format)
super(text_entries, typographies, output_directory)
@generate_binary_translations = generate_binary_translations
@generate_font_format = generate_font_format
@cache = {}
end
def run
#compute the typed text table once
compute_typed_texts
#calculate the cache map
#first the layout databases
databases = {}
layouts.each do |l|
tts = typed_texts(l)
tt_db = []
tts.inject(tt_db) do |a, tt|
#each text has a font index, alignment and direction
fontIdx = fontmap["getFont_#{tt.typography.cpp_name}_#{tt.typography.font_size}_#{tt.typography.bpp}bpp"]
a << [fontIdx, tt.alignment.upcase, tt.direction.upcase]
end
databases[l] = tt_db
end
#now the list of typed text databases
language_db_list = []
text_entries.languages.inject(language_db_list) do |list, lang|
list << (layouts.find{|l|l==lang}||'DEFAULT');list
end
@cache["databases"] = databases
@cache["database_list"]=language_db_list
@cache["fonts"] = fontmap
@cache["generate_font_format"] = @generate_font_format
new_cache_file = false
if not File::exists?(cache_file)
new_cache_file = true
else
#cache file exists, compare data with cache file
old_cache = JSON.parse(File.read(cache_file))
new_cache_file = (old_cache != @cache)
end
if new_cache_file
#write new cache file
FileIO.write_file_silent(cache_file, @cache.to_json)
end
if (!File::exists?(output_filename)) || new_cache_file
#generate TypedTextDatabase.cpp
super
end
end
def typed_texts(layout)
@typed_texts[layout]
end
def compute_typed_texts
@typed_texts = {}
layouts.each do |layout|
@typed_texts[layout] = text_entries.collect do |entry|
typography_name = entry.typographies[layout] || entry.typography
typography = typographies.find { |t| t.name == typography_name }
alignment = entry.alignments[layout] || entry.alignment
direction = entry.directions[layout] || entry.direction
TypedTextPresenter.new(alignment, direction, typography);
end
end
end
def generate_binary_files?
@generate_binary_translations=="yes"
end
def layouts
@layouts ||=
begin
if text_entries.empty?
["DEFAULT"]
else
(text_entries.first.typographies.keys + text_entries.first.alignments.keys + text_entries.first.directions.keys << "DEFAULT").uniq
end
end
end
def fonts
@fonts ||=
begin
typographies.map{ |t| Typography.new("", t.font_file, t.font_size, t.bpp) }.uniq.collect do |f|
"getFont_#{f.cpp_name}_#{f.font_size}_#{f.bpp}bpp"
end
end
end
def fontmap
@fontmap ||=
begin
@fontmap = Hash.new
fonts.each_with_index do |f, i|
fontmap[f] = i
end
fontmap
end
end
def font_class_name
@generate_font_format == "1" ? "UnmappedDataFont" : "GeneratedFont"
end
def input_path
File.join(root_dir,'Templates','TypedTextDatabase.cpp.temp')
end
def output_path
'src/TypedTextDatabase.cpp'
end
def cache_file
File.join(@output_directory, 'cache/TypedTextDatabaseCpp.cache')
end
def output_filename
File.join(@output_directory, output_path)
end
end

View File

@ -0,0 +1,30 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
# All rights reserved.</center></h2>
#
# This software component is licensed by ST under Ultimate Liberty license
# SLA0044, the "License"; You may not use this file except in compliance with
# the License. You may obtain a copy of the License at:
# www.st.com/SLA0044
#
##############################################################################
class TypedTextDatabaseHpp < Template
def input_path
File.join(root_dir,'Templates','TypedTextDatabase.hpp.temp')
end
def output_path
'include/texts/TypedTextDatabase.hpp'
end
def output_filename
File.join(@output_directory, output_path)
end
def run
if (!File::exists?(output_filename))
#generate TypedTextDatabase.hpp
super
end
end
end

View File

@ -0,0 +1,542 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
# All rights reserved.</center></h2>
#
# This software component is licensed by ST under Ultimate Liberty license
# SLA0044, the "License"; You may not use this file except in compliance with
# the License. You may obtain a copy of the License at:
# www.st.com/SLA0044
#
##############################################################################
class UnicodesTxt
def initialize(text_entries, typographies, output_directory)
@text_entries = text_entries
@typographies = typographies
@output_directory = output_directory
end
def run
unique_typographies = @typographies.map{ |t| Typography.new("", t.font_file, t.font_size, t.bpp) }.uniq.sort_by { |t| sprintf("%s %04d %d",t.font_file,t.font_size,t.bpp) }
unique_typographies.each do |unique_typography|
UnicodeForTypographyTxt.new(@text_entries, @output_directory, @typographies, unique_typography).run
end
end
end
class UnicodeForTypographyTxt
def initialize(text_entries, output_directory, typographies, unique_typography)
@text_entries = text_entries
@output_directory = output_directory
@typographies = typographies
@unique_typography = unique_typography
end
def convert_to_contextual_forms(unicodes)
unicodes.sort!
[
[[0x0621],[0xFE80]], # ARABIC LETTER HAMZA
[[0x0622],[0xFE81,0xFE82]], # ARABIC LETTER ALEF WITH MADDA ABOVE
[[0x0622,0x0644],[0xFEF5,0xFEF6]], # ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE
[[0x0623],[0xFE83,0xFE84]], # ARABIC LETTER ALEF WITH HAMZA ABOVE
[[0x0623,0x0644],[0xFEF7,0xFEF8]], # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE
[[0x0624],[0xFE85,0xFE86]], # ARABIC LETTER WAW WITH HAMZA ABOVE
[[0x0625],[0xFE87,0xFE88]], # ARABIC LETTER ALEF WITH HAMZA BELOW
[[0x0625,0x0644],[0xFEF9,0xFEFA]], # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW
[[0x0626],[0xFE89,0xFE8A,0xFE8B,0xFE8C]], # ARABIC LETTER YEH WITH HAMZA ABOVE
[[0x0626,0x0627],[0xFBEA,0xFBEB]], # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF
[[0x0626,0x062C],[0xFC00,0xFC97]], # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH JEEM
[[0x0626,0x062D],[0xFC01,0xFC98]], # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HAH
[[0x0626,0x062E],[0xFC99]], # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH KHAH
[[0x0626,0x0631],[0xFC64]], # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH REH
[[0x0626,0x0632],[0xFC65]], # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ZAIN
[[0x0626,0x0645],[0xFC02,0xFC66,0xFC9A,0xFCDF]], # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM
[[0x0626,0x0646],[0xFC67]], # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH NOON
[[0x0626,0x0647],[0xFC9B,0xFCE0]], # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HEH
[[0x0626,0x0648],[0xFBEE,0xFBEF]], # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH WAW
[[0x0626,0x0649],[0xFBF9,0xFBFA,0xFBFB,0xFC03,0xFC68]], # ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA / ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA
[[0x0626,0x064A],[0xFC04,0xFC69]], # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YEH
[[0x0626,0x06C6],[0xFBF2,0xFBF3]], # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH OE
[[0x0626,0x06C7],[0xFBF0,0xFBF1]], # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U
[[0x0626,0x06C8],[0xFBF4,0xFBF5]], # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YU
[[0x0626,0x06D0],[0xFBF6,0xFBF7,0xFBF8]], # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E
[[0x0626,0x06D5],[0xFBEC,0xFBED]], # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE
[[0x0627],[0xFE8D,0xFE8E]], # ARABIC LETTER ALEF
[[0x0627,0x0628,0x0631,0x0643],[0xFDF3]], # ARABIC LIGATURE AKBAR
[[0x0627,0x0631,0x0644,0x06CC],[0xFDFC]], # RIAL SIGN
[[0x0627,0x0643],[0xFC37,0xFC80]], # ARABIC LIGATURE KAF WITH ALEF
[[0x0627,0x0644],[0xFEFB,0xFEFC]], # ARABIC LIGATURE LAM WITH ALEF
[[0x0627,0x0644,0x0647],[0xFDF2]], # ARABIC LIGATURE ALLAH
[[0x0627,0x0645],[0xFC88]], # ARABIC LIGATURE MEEM WITH ALEF
[[0x0627,0x064B],[0xFD3C,0xFD3D]], # ARABIC LIGATURE ALEF WITH FATHATAN
[[0x0628],[0xFE8F,0xFE90,0xFE91,0xFE92]], # ARABIC LETTER BEH
[[0x0628,0x062C],[0xFC05,0xFC9C]], # ARABIC LIGATURE BEH WITH JEEM
[[0x0628,0x062D],[0xFC06,0xFC9D]], # ARABIC LIGATURE BEH WITH HAH
[[0x0628,0x062D,0x064A],[0xFDC2]], # ARABIC LIGATURE BEH WITH HAH WITH YEH
[[0x0628,0x062E],[0xFC07,0xFC9E]], # ARABIC LIGATURE BEH WITH KHAH
[[0x0628,0x062E,0x064A],[0xFD9E]], # ARABIC LIGATURE BEH WITH KHAH WITH YEH
[[0x0628,0x0631],[0xFC6A]], # ARABIC LIGATURE BEH WITH REH
[[0x0628,0x0632],[0xFC6B]], # ARABIC LIGATURE BEH WITH ZAIN
[[0x0628,0x0645],[0xFC08,0xFC6C,0xFC9F,0xFCE1]], # ARABIC LIGATURE BEH WITH MEEM
[[0x0628,0x0646],[0xFC6D]], # ARABIC LIGATURE BEH WITH NOON
[[0x0628,0x0647],[0xFCA0,0xFCE2]], # ARABIC LIGATURE BEH WITH HEH
[[0x0628,0x0649],[0xFC09,0xFC6E]], # ARABIC LIGATURE BEH WITH ALEF MAKSURA
[[0x0628,0x064A],[0xFC0A,0xFC6F]], # ARABIC LIGATURE BEH WITH YEH
[[0x0629],[0xFE93,0xFE94]], # ARABIC LETTER TEH MARBUTA
[[0x062A],[0xFE95,0xFE96,0xFE97,0xFE98]], # ARABIC LETTER TEH
[[0x062A,0x062C],[0xFC0B,0xFCA1]], # ARABIC LIGATURE TEH WITH JEEM
[[0x062A,0x062C,0x062D],[0xFD51,0xFD52]], # ARABIC LIGATURE TEH WITH HAH WITH JEEM
[[0x062A,0x062C,0x0645],[0xFD50,0xFD55]], # ARABIC LIGATURE TEH WITH JEEM WITH MEEM / ARABIC LIGATURE TEH WITH MEEM WITH JEEM
[[0x062A,0x062C,0x0649],[0xFDA0]], # ARABIC LIGATURE TEH WITH JEEM WITH ALEF MAKSURA
[[0x062A,0x062C,0x064A],[0xFD9F]], # ARABIC LIGATURE TEH WITH JEEM WITH YEH
[[0x062A,0x062D],[0xFC0C,0xFCA2]], # ARABIC LIGATURE TEH WITH HAH
[[0x062A,0x062D,0x0645],[0xFD53,0xFD56]], # ARABIC LIGATURE TEH WITH HAH WITH MEEM / ARABIC LIGATURE TEH WITH MEEM WITH HAH
[[0x062A,0x062E],[0xFC0D,0xFCA3]], # ARABIC LIGATURE TEH WITH KHAH
[[0x062A,0x062E,0x0645],[0xFD54,0xFD57]], # ARABIC LIGATURE TEH WITH KHAH WITH MEEM / ARABIC LIGATURE TEH WITH MEEM WITH KHAH
[[0x062A,0x062E,0x0649],[0xFDA2]], # ARABIC LIGATURE TEH WITH KHAH WITH ALEF MAKSURA
[[0x062A,0x062E,0x064A],[0xFDA1]], # ARABIC LIGATURE TEH WITH KHAH WITH YEH
[[0x062A,0x0631],[0xFC70]], # ARABIC LIGATURE TEH WITH REH
[[0x062A,0x0632],[0xFC71]], # ARABIC LIGATURE TEH WITH ZAIN
[[0x062A,0x0645],[0xFC0E,0xFC72,0xFCA4,0xFCE3]], # ARABIC LIGATURE TEH WITH MEEM
[[0x062A,0x0645,0x0649],[0xFDA4]], # ARABIC LIGATURE TEH WITH MEEM WITH ALEF MAKSURA
[[0x062A,0x0645,0x064A],[0xFDA3]], # ARABIC LIGATURE TEH WITH MEEM WITH YEH
[[0x062A,0x0646],[0xFC73]], # ARABIC LIGATURE TEH WITH NOON
[[0x062A,0x0647],[0xFCA5,0xFCE4]], # ARABIC LIGATURE TEH WITH HEH
[[0x062A,0x0649],[0xFC0F,0xFC74]], # ARABIC LIGATURE TEH WITH ALEF MAKSURA
[[0x062A,0x064A],[0xFC10,0xFC75]], # ARABIC LIGATURE TEH WITH YEH
[[0x062B],[0xFE99,0xFE9A,0xFE9B,0xFE9C]], # ARABIC LETTER THEH
[[0x062B,0x062C],[0xFC11]], # ARABIC LIGATURE THEH WITH JEEM
[[0x062B,0x0631],[0xFC76]], # ARABIC LIGATURE THEH WITH REH
[[0x062B,0x0632],[0xFC77]], # ARABIC LIGATURE THEH WITH ZAIN
[[0x062B,0x0645],[0xFC12,0xFC78,0xFCA6,0xFCE5]], # ARABIC LIGATURE THEH WITH MEEM
[[0x062B,0x0646],[0xFC79]], # ARABIC LIGATURE THEH WITH NOON
[[0x062B,0x0647],[0xFCE6]], # ARABIC LIGATURE THEH WITH HEH
[[0x062B,0x0649],[0xFC13,0xFC7A]], # ARABIC LIGATURE THEH WITH ALEF MAKSURA
[[0x062B,0x064A],[0xFC14,0xFC7B]], # ARABIC LIGATURE THEH WITH YEH
[[0x062C],[0xFE9D,0xFE9E,0xFE9F,0xFEA0]], # ARABIC LETTER JEEM
[[0x062C,0x062D],[0xFC15,0xFC17,0xFCA7,0xFCA9]], # ARABIC LIGATURE JEEM WITH HAH / ARABIC LIGATURE HAH WITH JEEM
[[0x062C,0x062D,0x0633],[0xFD5C,0xFD5D]], # ARABIC LIGATURE SEEN WITH HAH WITH JEEM / ARABIC LIGATURE SEEN WITH JEEM WITH HAH
[[0x062C,0x062D,0x0645],[0xFD58,0xFD59,0xFD89,0xFD8C]], # ARABIC LIGATURE JEEM WITH MEEM WITH HAH / ARABIC LIGATURE MEEM WITH HAH WITH JEEM / ARABIC LIGATURE MEEM WITH JEEM WITH HAH
[[0x062C,0x062D,0x0646],[0xFDB8,0xFDBD]], # ARABIC LIGATURE NOON WITH JEEM WITH HAH
[[0x062C,0x062D,0x0649],[0xFDA6]], # ARABIC LIGATURE JEEM WITH HAH WITH ALEF MAKSURA
[[0x062C,0x062D,0x064A],[0xFDBE,0xFDBF]], # ARABIC LIGATURE JEEM WITH HAH WITH YEH / ARABIC LIGATURE HAH WITH JEEM WITH YEH
[[0x062C,0x062E],[0xFC19,0xFCAB]], # ARABIC LIGATURE KHAH WITH JEEM
[[0x062C,0x062E,0x0645],[0xFD8E,0xFD92]], # ARABIC LIGATURE MEEM WITH KHAH WITH JEEM / ARABIC LIGATURE MEEM WITH JEEM WITH KHAH
[[0x062C,0x0633],[0xFC1C,0xFCAD,0xFD34]], # ARABIC LIGATURE SEEN WITH JEEM
[[0x062C,0x0633,0x0645],[0xFD61]], # ARABIC LIGATURE SEEN WITH MEEM WITH JEEM
[[0x062C,0x0633,0x0649],[0xFD5E]], # ARABIC LIGATURE SEEN WITH JEEM WITH ALEF MAKSURA
[[0x062C,0x0634],[0xFD09,0xFD25,0xFD2D,0xFD37]], # ARABIC LIGATURE SHEEN WITH JEEM
[[0x062C,0x0634,0x064A],[0xFD69]], # ARABIC LIGATURE SHEEN WITH JEEM WITH YEH
[[0x062C,0x0636],[0xFC22,0xFCB4]], # ARABIC LIGATURE DAD WITH JEEM
[[0x062C,0x0639],[0xFC29,0xFCBA]], # ARABIC LIGATURE AIN WITH JEEM
[[0x062C,0x0639,0x0645],[0xFD75,0xFDC4]], # ARABIC LIGATURE AIN WITH JEEM WITH MEEM
[[0x062C,0x063A],[0xFC2B,0xFCBC]], # ARABIC LIGATURE GHAIN WITH JEEM
[[0x062C,0x0641],[0xFC2D,0xFCBE]], # ARABIC LIGATURE FEH WITH JEEM
[[0x062C,0x0643],[0xFC38,0xFCC4]], # ARABIC LIGATURE KAF WITH JEEM
[[0x062C,0x0644],[0xFC3F,0xFCC9,0xFD83,0xFD84]], # ARABIC LIGATURE LAM WITH JEEM / ARABIC LIGATURE LAM WITH JEEM WITH JEEM
[[0x062C,0x0644,0x0645],[0xFDBA,0xFDBC]], # ARABIC LIGATURE LAM WITH JEEM WITH MEEM
[[0x062C,0x0644,0x064A],[0xFDAC]], # ARABIC LIGATURE LAM WITH JEEM WITH YEH
[[0x062C,0x0645],[0xFC16,0xFC45,0xFCA8,0xFCCE,0xFD8D]], # ARABIC LIGATURE JEEM WITH MEEM / ARABIC LIGATURE MEEM WITH JEEM / ARABIC LIGATURE MEEM WITH JEEM WITH MEEM
[[0x062C,0x0645,0x0646],[0xFD97,0xFD98]], # ARABIC LIGATURE NOON WITH JEEM WITH MEEM
[[0x062C,0x0645,0x0647],[0xFD93]], # ARABIC LIGATURE HEH WITH MEEM WITH JEEM
[[0x062C,0x0645,0x0649],[0xFDA7]], # ARABIC LIGATURE JEEM WITH MEEM WITH ALEF MAKSURA
[[0x062C,0x0645,0x064A],[0xFDA5,0xFDC0]], # ARABIC LIGATURE JEEM WITH MEEM WITH YEH / ARABIC LIGATURE MEEM WITH JEEM WITH YEH
[[0x062C,0x0646],[0xFC4B,0xFCD2]], # ARABIC LIGATURE NOON WITH JEEM
[[0x062C,0x0646,0x0649],[0xFD99]], # ARABIC LIGATURE NOON WITH JEEM WITH ALEF MAKSURA
[[0x062C,0x0646,0x064A],[0xFDC7]], # ARABIC LIGATURE NOON WITH JEEM WITH YEH
[[0x062C,0x0647],[0xFC51,0xFCD7]], # ARABIC LIGATURE HEH WITH JEEM
[[0x062C,0x0649],[0xFD01,0xFD1D]], # ARABIC LIGATURE JEEM WITH ALEF MAKSURA
[[0x062C,0x064A],[0xFC55,0xFCDA,0xFD02,0xFD1E,0xFDAF]], # ARABIC LIGATURE YEH WITH JEEM / ARABIC LIGATURE JEEM WITH YEH / ARABIC LIGATURE YEH WITH JEEM WITH YEH
[[0x062D],[0xFEA1,0xFEA2,0xFEA3,0xFEA4]], # ARABIC LETTER HAH
[[0x062D,0x062E],[0xFC1A]], # ARABIC LIGATURE KHAH WITH HAH
[[0x062D,0x062F,0x0645],[0xFDF4]], # ARABIC LIGATURE MOHAMMAD
[[0x062D,0x0633],[0xFC1D,0xFCAE,0xFD35]], # ARABIC LIGATURE SEEN WITH HAH
[[0x062D,0x0633,0x0645],[0xFD5F,0xFD60]], # ARABIC LIGATURE SEEN WITH MEEM WITH HAH
[[0x062D,0x0634],[0xFD0A,0xFD26,0xFD2E,0xFD38]], # ARABIC LIGATURE SHEEN WITH HAH
[[0x062D,0x0634,0x0645],[0xFD67,0xFD68]], # ARABIC LIGATURE SHEEN WITH HAH WITH MEEM
[[0x062D,0x0634,0x064A],[0xFDAA]], # ARABIC LIGATURE SHEEN WITH HAH WITH YEH
[[0x062D,0x0635],[0xFC20,0xFCB1,0xFD64,0xFD65]], # ARABIC LIGATURE SAD WITH HAH / ARABIC LIGATURE SAD WITH HAH WITH HAH
[[0x062D,0x0635,0x064A],[0xFDA9]], # ARABIC LIGATURE SAD WITH HAH WITH YEH
[[0x062D,0x0636],[0xFC23,0xFCB5]], # ARABIC LIGATURE DAD WITH HAH
[[0x062D,0x0636,0x0649],[0xFD6E]], # ARABIC LIGATURE DAD WITH HAH WITH ALEF MAKSURA
[[0x062D,0x0636,0x064A],[0xFDAB]], # ARABIC LIGATURE DAD WITH HAH WITH YEH
[[0x062D,0x0637],[0xFC26,0xFCB8]], # ARABIC LIGATURE TAH WITH HAH
[[0x062D,0x0637,0x0645],[0xFD71,0xFD72]], # ARABIC LIGATURE TAH WITH MEEM WITH HAH
[[0x062D,0x0641],[0xFC2E,0xFCBF]], # ARABIC LIGATURE FEH WITH HAH
[[0x062D,0x0642],[0xFC33,0xFCC2]], # ARABIC LIGATURE QAF WITH HAH
[[0x062D,0x0642,0x0645],[0xFD7E,0xFDB4]], # ARABIC LIGATURE QAF WITH MEEM WITH HAH
[[0x062D,0x0643],[0xFC39,0xFCC5]], # ARABIC LIGATURE KAF WITH HAH
[[0x062D,0x0644],[0xFC40,0xFCCA]], # ARABIC LIGATURE LAM WITH HAH
[[0x062D,0x0644,0x0645],[0xFD80,0xFD87,0xFD88,0xFDB5]], # ARABIC LIGATURE LAM WITH HAH WITH MEEM / ARABIC LIGATURE LAM WITH MEEM WITH HAH
[[0x062D,0x0644,0x0649],[0xFD82]], # ARABIC LIGATURE LAM WITH HAH WITH ALEF MAKSURA
[[0x062D,0x0644,0x064A],[0xFD81]], # ARABIC LIGATURE LAM WITH HAH WITH YEH
[[0x062D,0x0645],[0xFC18,0xFC46,0xFCAA,0xFCCF,0xFD8A]], # ARABIC LIGATURE HAH WITH MEEM / ARABIC LIGATURE MEEM WITH HAH / ARABIC LIGATURE MEEM WITH HAH WITH MEEM
[[0x062D,0x0645,0x0646],[0xFD95]], # ARABIC LIGATURE NOON WITH HAH WITH MEEM
[[0x062D,0x0645,0x0649],[0xFD5B]], # ARABIC LIGATURE HAH WITH MEEM WITH ALEF MAKSURA
[[0x062D,0x0645,0x064A],[0xFD5A,0xFD8B]], # ARABIC LIGATURE HAH WITH MEEM WITH YEH / ARABIC LIGATURE MEEM WITH HAH WITH YEH
[[0x062D,0x0646],[0xFC4C,0xFCD3]], # ARABIC LIGATURE NOON WITH HAH
[[0x062D,0x0646,0x0649],[0xFD96]], # ARABIC LIGATURE NOON WITH HAH WITH ALEF MAKSURA
[[0x062D,0x0646,0x064A],[0xFDB3]], # ARABIC LIGATURE NOON WITH HAH WITH YEH
[[0x062D,0x0649],[0xFCFF,0xFD1B]], # ARABIC LIGATURE HAH WITH ALEF MAKSURA
[[0x062D,0x064A],[0xFC56,0xFCDB,0xFD00,0xFD1C,0xFDAE]], # ARABIC LIGATURE YEH WITH HAH / ARABIC LIGATURE HAH WITH YEH / ARABIC LIGATURE YEH WITH HAH WITH YEH
[[0x062E],[0xFEA5,0xFEA6,0xFEA7,0xFEA8]], # ARABIC LETTER KHAH
[[0x062E,0x0633],[0xFC1E,0xFCAF,0xFD36]], # ARABIC LIGATURE SEEN WITH KHAH
[[0x062E,0x0633,0x0649],[0xFDA8]], # ARABIC LIGATURE SEEN WITH KHAH WITH ALEF MAKSURA
[[0x062E,0x0633,0x064A],[0xFDC6]], # ARABIC LIGATURE SEEN WITH KHAH WITH YEH
[[0x062E,0x0634],[0xFD0B,0xFD27,0xFD2F,0xFD39]], # ARABIC LIGATURE SHEEN WITH KHAH
[[0x062E,0x0634,0x0645],[0xFD6A,0xFD6B]], # ARABIC LIGATURE SHEEN WITH MEEM WITH KHAH
[[0x062E,0x0635],[0xFCB2]], # ARABIC LIGATURE SAD WITH KHAH
[[0x062E,0x0636],[0xFC24,0xFCB6]], # ARABIC LIGATURE DAD WITH KHAH
[[0x062E,0x0636,0x0645],[0xFD6F,0xFD70]], # ARABIC LIGATURE DAD WITH KHAH WITH MEEM
[[0x062E,0x0641],[0xFC2F,0xFCC0]], # ARABIC LIGATURE FEH WITH KHAH
[[0x062E,0x0641,0x0645],[0xFD7C,0xFD7D]], # ARABIC LIGATURE FEH WITH KHAH WITH MEEM
[[0x062E,0x0643],[0xFC3A,0xFCC6]], # ARABIC LIGATURE KAF WITH KHAH
[[0x062E,0x0644],[0xFC41,0xFCCB]], # ARABIC LIGATURE LAM WITH KHAH
[[0x062E,0x0644,0x0645],[0xFD85,0xFD86]], # ARABIC LIGATURE LAM WITH KHAH WITH MEEM
[[0x062E,0x0645],[0xFC1B,0xFC47,0xFCAC,0xFCD0,0xFD8F]], # ARABIC LIGATURE KHAH WITH MEEM / ARABIC LIGATURE MEEM WITH KHAH / ARABIC LIGATURE MEEM WITH KHAH WITH MEEM
[[0x062E,0x0645,0x064A],[0xFDB9]], # ARABIC LIGATURE MEEM WITH KHAH WITH YEH
[[0x062E,0x0646],[0xFC4D,0xFCD4]], # ARABIC LIGATURE NOON WITH KHAH
[[0x062E,0x0649],[0xFD03,0xFD1F]], # ARABIC LIGATURE KHAH WITH ALEF MAKSURA
[[0x062E,0x064A],[0xFC57,0xFCDC,0xFD04,0xFD20]], # ARABIC LIGATURE YEH WITH KHAH / ARABIC LIGATURE KHAH WITH YEH
[[0x062F],[0xFEA9,0xFEAA]], # ARABIC LETTER DAL
[[0x0630],[0xFEAB,0xFEAC]], # ARABIC LETTER THAL
[[0x0630,0x0670],[0xFC5B]], # ARABIC LIGATURE THAL WITH SUPERSCRIPT ALEF
[[0x0631],[0xFEAD,0xFEAE]], # ARABIC LETTER REH
[[0x0631,0x0633],[0xFD0E,0xFD2A]], # ARABIC LIGATURE SEEN WITH REH
[[0x0631,0x0633,0x0644,0x0648],[0xFDF6]], # ARABIC LIGATURE RASOUL
[[0x0631,0x0634],[0xFD0D,0xFD29]], # ARABIC LIGATURE SHEEN WITH REH
[[0x0631,0x0635],[0xFD0F,0xFD2B]], # ARABIC LIGATURE SAD WITH REH
[[0x0631,0x0636],[0xFD10,0xFD2C]], # ARABIC LIGATURE DAD WITH REH
[[0x0631,0x0646],[0xFC8A]], # ARABIC LIGATURE NOON WITH REH
[[0x0631,0x064A],[0xFC91]], # ARABIC LIGATURE YEH WITH REH
[[0x0631,0x0670],[0xFC5C]], # ARABIC LIGATURE REH WITH SUPERSCRIPT ALEF
[[0x0632],[0xFEAF,0xFEB0]], # ARABIC LETTER ZAIN
[[0x0632,0x0646],[0xFC8B]], # ARABIC LIGATURE NOON WITH ZAIN
[[0x0632,0x064A],[0xFC92]], # ARABIC LIGATURE YEH WITH ZAIN
[[0x0633],[0xFEB1,0xFEB2,0xFEB3,0xFEB4]], # ARABIC LETTER SEEN
[[0x0633,0x0644,0x0645,0x0648],[0xFDF8]], # ARABIC LIGATURE WASALLAM
[[0x0633,0x0645],[0xFC1F,0xFCB0,0xFCE7,0xFD62,0xFD63]], # ARABIC LIGATURE SEEN WITH MEEM / ARABIC LIGATURE SEEN WITH MEEM WITH MEEM
[[0x0633,0x0647],[0xFCE8,0xFD31]], # ARABIC LIGATURE SEEN WITH HEH
[[0x0633,0x0649],[0xFCFB,0xFD17]], # ARABIC LIGATURE SEEN WITH ALEF MAKSURA
[[0x0633,0x064A],[0xFCFC,0xFD18]], # ARABIC LIGATURE SEEN WITH YEH
[[0x0634],[0xFEB5,0xFEB6,0xFEB7,0xFEB8]], # ARABIC LETTER SHEEN
[[0x0634,0x0645],[0xFCE9,0xFD0C,0xFD28,0xFD30,0xFD6C,0xFD6D]], # ARABIC LIGATURE SHEEN WITH MEEM / ARABIC LIGATURE SHEEN WITH MEEM WITH MEEM
[[0x0634,0x0647],[0xFCEA,0xFD32]], # ARABIC LIGATURE SHEEN WITH HEH
[[0x0634,0x0649],[0xFCFD,0xFD19]], # ARABIC LIGATURE SHEEN WITH ALEF MAKSURA
[[0x0634,0x064A],[0xFCFE,0xFD1A]], # ARABIC LIGATURE SHEEN WITH YEH
[[0x0635],[0xFEB9,0xFEBA,0xFEBB,0xFEBC]], # ARABIC LETTER SAD
[[0x0635,0x0639,0x0644,0x0645],[0xFDF5]], # ARABIC LIGATURE SALAM
[[0x0635,0x0644,0x0649],[0xFDF9]], # ARABIC LIGATURE SALLA
[[0x0635,0x0644,0x06D2],[0xFDF0]], # ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN
[[0x0635,0x0645],[0xFC21,0xFCB3,0xFD66,0xFDC5]], # ARABIC LIGATURE SAD WITH MEEM / ARABIC LIGATURE SAD WITH MEEM WITH MEEM
[[0x0635,0x0649],[0xFD05,0xFD21]], # ARABIC LIGATURE SAD WITH ALEF MAKSURA
[[0x0635,0x064A],[0xFD06,0xFD22]], # ARABIC LIGATURE SAD WITH YEH
[[0x0636],[0xFEBD,0xFEBE,0xFEBF,0xFEC0]], # ARABIC LETTER DAD
[[0x0636,0x0645],[0xFC25,0xFCB7]], # ARABIC LIGATURE DAD WITH MEEM
[[0x0636,0x0649],[0xFD07,0xFD23]], # ARABIC LIGATURE DAD WITH ALEF MAKSURA
[[0x0636,0x064A],[0xFD08,0xFD24]], # ARABIC LIGATURE DAD WITH YEH
[[0x0637],[0xFEC1,0xFEC2,0xFEC3,0xFEC4]], # ARABIC LETTER TAH
[[0x0637,0x0645],[0xFC27,0xFD33,0xFD3A,0xFD73]], # ARABIC LIGATURE TAH WITH MEEM / ARABIC LIGATURE TAH WITH MEEM WITH MEEM
[[0x0637,0x0645,0x064A],[0xFD74]], # ARABIC LIGATURE TAH WITH MEEM WITH YEH
[[0x0637,0x0649],[0xFCF5,0xFD11]], # ARABIC LIGATURE TAH WITH ALEF MAKSURA
[[0x0637,0x064A],[0xFCF6,0xFD12]], # ARABIC LIGATURE TAH WITH YEH
[[0x0638],[0xFEC5,0xFEC6,0xFEC7,0xFEC8]], # ARABIC LETTER ZAH
[[0x0638,0x0645],[0xFC28,0xFCB9,0xFD3B]], # ARABIC LIGATURE ZAH WITH MEEM
[[0x0639],[0xFEC9,0xFECA,0xFECB,0xFECC]], # ARABIC LETTER AIN
[[0x0639,0x0644,0x0647,0x064A],[0xFDF7]], # ARABIC LIGATURE ALAYHE
[[0x0639,0x0645],[0xFC2A,0xFCBB,0xFD76,0xFD77]], # ARABIC LIGATURE AIN WITH MEEM / ARABIC LIGATURE AIN WITH MEEM WITH MEEM
[[0x0639,0x0645,0x0649],[0xFD78]], # ARABIC LIGATURE AIN WITH MEEM WITH ALEF MAKSURA
[[0x0639,0x0645,0x064A],[0xFDB6]], # ARABIC LIGATURE AIN WITH MEEM WITH YEH
[[0x0639,0x0649],[0xFCF7,0xFD13]], # ARABIC LIGATURE AIN WITH ALEF MAKSURA
[[0x0639,0x064A],[0xFCF8,0xFD14]], # ARABIC LIGATURE AIN WITH YEH
[[0x063A],[0xFECD,0xFECE,0xFECF,0xFED0]], # ARABIC LETTER GHAIN
[[0x063A,0x0645],[0xFC2C,0xFCBD,0xFD79]], # ARABIC LIGATURE GHAIN WITH MEEM / ARABIC LIGATURE GHAIN WITH MEEM WITH MEEM
[[0x063A,0x0645,0x0649],[0xFD7B]], # ARABIC LIGATURE GHAIN WITH MEEM WITH ALEF MAKSURA
[[0x063A,0x0645,0x064A],[0xFD7A]], # ARABIC LIGATURE GHAIN WITH MEEM WITH YEH
[[0x063A,0x0649],[0xFCF9,0xFD15]], # ARABIC LIGATURE GHAIN WITH ALEF MAKSURA
[[0x063A,0x064A],[0xFCFA,0xFD16]], # ARABIC LIGATURE GHAIN WITH YEH
[[0x0640,0x064B],[0xFE71]], # ARABIC TATWEEL WITH FATHATAN ABOVE
[[0x0640,0x064E],[0xFE77]], # ARABIC FATHA
[[0x0640,0x064E,0x0651],[0xFCF2]], # ARABIC LIGATURE SHADDA WITH FATHA
[[0x0640,0x064F],[0xFE79]], # ARABIC DAMMA
[[0x0640,0x064F,0x0651],[0xFCF3]], # ARABIC LIGATURE SHADDA WITH DAMMA
[[0x0640,0x0650],[0xFE7B]], # ARABIC KASRA
[[0x0640,0x0650,0x0651],[0xFCF4]], # ARABIC LIGATURE SHADDA WITH KASRA
[[0x0640,0x0651],[0xFE7D]], # ARABIC SHADDA
[[0x0640,0x0652],[0xFE7F]], # ARABIC SUKUN
[[0x0641],[0xFED1,0xFED2,0xFED3,0xFED4]], # ARABIC LETTER FEH
[[0x0641,0x0645],[0xFC30,0xFCC1]], # ARABIC LIGATURE FEH WITH MEEM
[[0x0641,0x0645,0x064A],[0xFDC1]], # ARABIC LIGATURE FEH WITH MEEM WITH YEH
[[0x0641,0x0649],[0xFC31,0xFC7C]], # ARABIC LIGATURE FEH WITH ALEF MAKSURA
[[0x0641,0x064A],[0xFC32,0xFC7D]], # ARABIC LIGATURE FEH WITH YEH
[[0x0642],[0xFED5,0xFED6,0xFED7,0xFED8]], # ARABIC LETTER QAF
[[0x0642,0x0644,0x06D2],[0xFDF1]], # ARABIC LIGATURE QALA USED AS KORANIC STOP SIGN
[[0x0642,0x0645],[0xFC34,0xFCC3,0xFD7F]], # ARABIC LIGATURE QAF WITH MEEM / ARABIC LIGATURE QAF WITH MEEM WITH MEEM
[[0x0642,0x0645,0x064A],[0xFDB2]], # ARABIC LIGATURE QAF WITH MEEM WITH YEH
[[0x0642,0x0649],[0xFC35,0xFC7E]], # ARABIC LIGATURE QAF WITH ALEF MAKSURA
[[0x0642,0x064A],[0xFC36,0xFC7F]], # ARABIC LIGATURE QAF WITH YEH
[[0x0643],[0xFED9,0xFEDA,0xFEDB,0xFEDC]], # ARABIC LETTER KAF
[[0x0643,0x0644],[0xFC3B,0xFC81,0xFCC7,0xFCEB]], # ARABIC LIGATURE KAF WITH LAM
[[0x0643,0x0645],[0xFC3C,0xFC82,0xFCC8,0xFCEC,0xFDBB,0xFDC3]], # ARABIC LIGATURE KAF WITH MEEM / ARABIC LIGATURE KAF WITH MEEM WITH MEEM
[[0x0643,0x0645,0x064A],[0xFDB7]], # ARABIC LIGATURE KAF WITH MEEM WITH YEH
[[0x0643,0x0649],[0xFC3D,0xFC83]], # ARABIC LIGATURE KAF WITH ALEF MAKSURA
[[0x0643,0x064A],[0xFC3E,0xFC84]], # ARABIC LIGATURE KAF WITH YEH
[[0x0644],[0xFEDD,0xFEDE,0xFEDF,0xFEE0]], # ARABIC LETTER LAM
[[0x0644,0x0645],[0xFC42,0xFC85,0xFCCC,0xFCED]], # ARABIC LIGATURE LAM WITH MEEM
[[0x0644,0x0645,0x064A],[0xFDAD]], # ARABIC LIGATURE LAM WITH MEEM WITH YEH
[[0x0644,0x0647],[0xFCCD]], # ARABIC LIGATURE LAM WITH HEH
[[0x0644,0x0649],[0xFC43,0xFC86]], # ARABIC LIGATURE LAM WITH ALEF MAKSURA
[[0x0644,0x064A],[0xFC44,0xFC87]], # ARABIC LIGATURE LAM WITH YEH
[[0x0645],[0xFC48,0xFC89,0xFCD1,0xFEE1,0xFEE2,0xFEE3,0xFEE4]], # ARABIC LIGATURE MEEM WITH MEEM / ARABIC LETTER MEEM
[[0x0645,0x0646],[0xFC4E,0xFC8C,0xFCD5,0xFCEE]], # ARABIC LIGATURE NOON WITH MEEM
[[0x0645,0x0646,0x0649],[0xFD9B]], # ARABIC LIGATURE NOON WITH MEEM WITH ALEF MAKSURA
[[0x0645,0x0646,0x064A],[0xFD9A]], # ARABIC LIGATURE NOON WITH MEEM WITH YEH
[[0x0645,0x0647],[0xFC52,0xFCD8,0xFD94]], # ARABIC LIGATURE HEH WITH MEEM / ARABIC LIGATURE HEH WITH MEEM WITH MEEM
[[0x0645,0x0649],[0xFC49]], # ARABIC LIGATURE MEEM WITH ALEF MAKSURA
[[0x0645,0x064A],[0xFC4A,0xFC58,0xFC93,0xFCDD,0xFCF0,0xFD9C,0xFD9D,0xFDB0,0xFDB1]], # ARABIC LIGATURE MEEM WITH YEH / ARABIC LIGATURE YEH WITH MEEM / ARABIC LIGATURE YEH WITH MEEM WITH MEEM / ARABIC LIGATURE YEH WITH MEEM WITH YEH / ARABIC LIGATURE MEEM WITH MEEM WITH YEH
[[0x0646],[0xFC8D,0xFEE5,0xFEE6,0xFEE7,0xFEE8]], # ARABIC LIGATURE NOON WITH NOON / ARABIC LETTER NOON
[[0x0646,0x0647],[0xFCD6,0xFCEF]], # ARABIC LIGATURE NOON WITH HEH
[[0x0646,0x0649],[0xFC4F,0xFC8E]], # ARABIC LIGATURE NOON WITH ALEF MAKSURA
[[0x0646,0x064A],[0xFC50,0xFC8F,0xFC94]], # ARABIC LIGATURE NOON WITH YEH / ARABIC LIGATURE YEH WITH NOON
[[0x0647],[0xFEE9,0xFEEA,0xFEEB,0xFEEC]], # ARABIC LETTER HEH
[[0x0647,0x0649],[0xFC53]], # ARABIC LIGATURE HEH WITH ALEF MAKSURA
[[0x0647,0x064A],[0xFC54,0xFCDE,0xFCF1]], # ARABIC LIGATURE HEH WITH YEH / ARABIC LIGATURE YEH WITH HEH
[[0x0647,0x0670],[0xFCD9]], # ARABIC LIGATURE HEH WITH SUPERSCRIPT ALEF
[[0x0648],[0xFEED,0xFEEE]], # ARABIC LETTER WAW
[[0x0649],[0xFBE8,0xFBE9,0xFEEF,0xFEF0]], # ARABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA / ARABIC LETTER ALEF MAKSURA
[[0x0649,0x064A],[0xFC59,0xFC95]], # ARABIC LIGATURE YEH WITH ALEF MAKSURA
[[0x0649,0x0670],[0xFC5D,0xFC90]], # ARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF
[[0x064A],[0xFC5A,0xFC96,0xFEF1,0xFEF2,0xFEF3,0xFEF4]], # ARABIC LIGATURE YEH WITH YEH / ARABIC LETTER YEH
[[0x064B],[0xFE70]], # ARABIC FATHATAN
[[0x064C],[0xFE72]], # ARABIC DAMMATAN
[[0x064C,0x0651],[0xFC5E]], # ARABIC LIGATURE SHADDA WITH DAMMATAN
[[0x064D],[0xFE74]], # ARABIC KASRATAN
[[0x064D,0x0651],[0xFC5F]], # ARABIC LIGATURE SHADDA WITH KASRATAN
[[0x064E],[0xFE76]], # ARABIC FATHA
[[0x064E,0x0651],[0xFC60]], # ARABIC LIGATURE SHADDA WITH FATHA
[[0x064F],[0xFE78]], # ARABIC DAMMA
[[0x064F,0x0651],[0xFC61]], # ARABIC LIGATURE SHADDA WITH DAMMA
[[0x0650],[0xFE7A]], # ARABIC KASRA
[[0x0650,0x0651],[0xFC62]], # ARABIC LIGATURE SHADDA WITH KASRA
[[0x0651],[0xFE7C]], # ARABIC SHADDA
[[0x0651,0x0670],[0xFC63]], # ARABIC LIGATURE SHADDA WITH SUPERSCRIPT ALEF
[[0x0652],[0xFE7E]], # ARABIC SUKUN
[[0x0671],[0xFB50,0xFB51]], # ARABIC LETTER ALEF WASLA
[[0x0677],[0xFBDD]], # ARABIC LETTER U WITH HAMZA ABOVE
[[0x0679],[0xFB66,0xFB67,0xFB68,0xFB69]], # ARABIC LETTER TTEH
[[0x067A],[0xFB5E,0xFB5F,0xFB60,0xFB61]], # ARABIC LETTER TTEHEH
[[0x067B],[0xFB52,0xFB53,0xFB54,0xFB55]], # ARABIC LETTER BEEH
[[0x067E],[0xFB56,0xFB57,0xFB58,0xFB59]], # ARABIC LETTER PEH
[[0x067F],[0xFB62,0xFB63,0xFB64,0xFB65]], # ARABIC LETTER TEHEH
[[0x0680],[0xFB5A,0xFB5B,0xFB5C,0xFB5D]], # ARABIC LETTER BEHEH
[[0x0683],[0xFB76,0xFB77,0xFB78,0xFB79]], # ARABIC LETTER NYEH
[[0x0684],[0xFB72,0xFB73,0xFB74,0xFB75]], # ARABIC LETTER DYEH
[[0x0686],[0xFB7A,0xFB7B,0xFB7C,0xFB7D]], # ARABIC LETTER TCHEH
[[0x0687],[0xFB7E,0xFB7F,0xFB80,0xFB81]], # ARABIC LETTER TCHEHEH
[[0x0688],[0xFB88,0xFB89]], # ARABIC LETTER DDAL
[[0x068C],[0xFB84,0xFB85]], # ARABIC LETTER DAHAL
[[0x068D],[0xFB82,0xFB83]], # ARABIC LETTER DDAHAL
[[0x068E],[0xFB86,0xFB87]], # ARABIC LETTER DUL
[[0x0691],[0xFB8C,0xFB8D]], # ARABIC LETTER RREH
[[0x0698],[0xFB8A,0xFB8B]], # ARABIC LETTER JEH
[[0x06A4],[0xFB6A,0xFB6B,0xFB6C,0xFB6D]], # ARABIC LETTER VEH
[[0x06A6],[0xFB6E,0xFB6F,0xFB70,0xFB71]], # ARABIC LETTER PEHEH
[[0x06A9],[0xFB8E,0xFB8F,0xFB90,0xFB91]], # ARABIC LETTER KEHEH
[[0x06AD],[0xFBD3,0xFBD4,0xFBD5,0xFBD6]], # ARABIC LETTER NG
[[0x06AF],[0xFB92,0xFB93,0xFB94,0xFB95]], # ARABIC LETTER GAF
[[0x06B1],[0xFB9A,0xFB9B,0xFB9C,0xFB9D]], # ARABIC LETTER NGOEH
[[0x06B3],[0xFB96,0xFB97,0xFB98,0xFB99]], # ARABIC LETTER GUEH
[[0x06BA],[0xFB9E,0xFB9F]], # ARABIC LETTER NOON GHUNNA
[[0x06BB],[0xFBA0,0xFBA1,0xFBA2,0xFBA3]], # ARABIC LETTER RNOON
[[0x06BE],[0xFBAA,0xFBAB,0xFBAC,0xFBAD]], # ARABIC LETTER HEH DOACHASHMEE
[[0x06C0],[0xFBA4,0xFBA5]], # ARABIC LETTER HEH WITH YEH ABOVE
[[0x06C1],[0xFBA6,0xFBA7,0xFBA8,0xFBA9]], # ARABIC LETTER HEH GOAL
[[0x06C5],[0xFBE0,0xFBE1]], # ARABIC LETTER KIRGHIZ OE
[[0x06C6],[0xFBD9,0xFBDA]], # ARABIC LETTER OE
[[0x06C7],[0xFBD7,0xFBD8]], # ARABIC LETTER U
[[0x06C8],[0xFBDB,0xFBDC]], # ARABIC LETTER YU
[[0x06C9],[0xFBE2,0xFBE3]], # ARABIC LETTER KIRGHIZ YU
[[0x06CB],[0xFBDE,0xFBDF]], # ARABIC LETTER VE
[[0x06CC],[0xFBFC,0xFBFD,0xFBFE,0xFBFF]], # ARABIC LETTER FARSI YEH
[[0x06D0],[0xFBE4,0xFBE5,0xFBE6,0xFBE7]], # ARABIC LETTER E
[[0x06D2],[0xFBAE,0xFBAF]], # ARABIC LETTER YEH BARREE
[[0x06D3],[0xFBB0,0xFBB1]], # ARABIC LETTER YEH BARREE WITH HAMZA ABOVE
[[0],[0]]
].each do |u,l|
if (unicodes & u) == u
unicodes += l
end
end
unicodes.uniq
end
def mirror_brackes(unicodes)
[['<','>'],['(',')'],['[',']'],['{','}']].each do |l,r|
has_l = unicodes.include?(l.ord)
has_r = unicodes.include?(r.ord)
unicodes.push(r.ord) if has_l and !has_r
unicodes.push(l.ord) if has_r and !has_l
end
unicodes
end
def add_thai(unicodes)
# Add Thai unicodes which are used to calculate diacritic positions when the Thai characters have special shapes.
[[0x0E09, 0x0E08],[0x0E13,0x0E0C],[0x0E19,0x0E18],[0x0E1B, 0x0E1A],[0x0E1D,0x0E1C],[0x0E1F,0x0E1E],[0x0E33,0x0E32],[0x0E33,0x0E4D]].each do |has,need|
has_unicode = unicodes.include?(has)
has_needed = unicodes.include?(need)
unicodes.push(need) if has_unicode and !has_needed
end
unicodes
end
def check_for_rtl(unicodes)
return if @text_entries.is_rtl # No need to look for unicode if RTL already detected
# Look for hebrew (0x0590-0x05ff) or arabic (0x0600-0x06ff) + arabic ligatures (0xFE70-0xFEFF)
@text_entries.unicode_uses_rtl if unicodes.any?{|u| u.between?(0x0590, 0x05FF) || u.between?(0x0600, 0x06FF) || u.between?(0xFE70, 0xFEFE) }
end
def decode_ranges(str)
result = []
while str.length > 0
char_range = str.match(/^(.)-(.)(.*)$/)
if char_range
first_char = char_range[1]
last_char = char_range[2]
result += (first_char.ord .. last_char.ord).to_a
str = char_range[3]
else
num_range = str.match(/^(0[xX][0-9a-fA-F]+|\d+)(?:\.0+)?-(0[xX][0-9a-fA-F]+|\d+)(?:\.0+)?(.*)$/)
if num_range
first_num = Integer(num_range[1])
last_num = Integer(num_range[2])
result += (first_num..last_num).to_a
str = num_range[3]
else
num = str.match(/^(0[xX][0-9a-fA-F]+|\d+)(?:\.0+)?(.*)/)
if num
# Check for typo such as 0,2-9
if num[1].length == 1
result += [ num[1].ord ]
else
result += [ Integer(num[1]) ]
end
str = num[2]
else
abort "Unexpected character at #{str}"
end
end
end
if str.length > 0
if str[0] == ','
str = str[1..-1]
else
abort "Please separate wildcard ranges with ','"
end
end
end
result
end
def run
typographies_identical = @typographies.select{ |t| t.font_file == @unique_typography.font_file &&
t.font_size == @unique_typography.font_size &&
t.bpp == @unique_typography.bpp }
typography_names = typographies_identical.map{ |t| t.name }.uniq
# Find a typography with a fallback character
typography_with_fallback_character = typographies_identical.find { |t| t.fallback_character }
if typography_with_fallback_character
# Now get the actual fallback character (or 'skip')
typography_fallback_character = typography_with_fallback_character.fallback_character
# Check to see if one of the other typographes has a different fallback character
index = typographies_identical.find_index{ |t| t.fallback_character && t.fallback_character != typography_fallback_character }
if index
abort "The fallback character differs for typography \"#{typography_with_fallback_character.name}\" and typography \"#{typographies_identical[index].name}\""
end
# set all fallback characters to the same character
typographies_identical.each { |t| t.fallback_character = typography_fallback_character }
end
# Find a typography with a ellipsis character
typography_with_ellipsis_character = typographies_identical.find { |t| t.ellipsis_character }
if typography_with_ellipsis_character
# Now get the actual ellipsis character (or 'skip')
typography_ellipsis_character = typography_with_ellipsis_character.ellipsis_character
# Check to see if one of the other typographes has a different ellipsis character
index = typographies_identical.find_index{ |t| t.ellipsis_character && t.ellipsis_character != typography_ellipsis_character }
if index
abort "The ellipsis character differs for typography \"#{typography_with_ellipsis_character.name}\" and typography \"#{typographies_identical[index].name}\""
end
# set all ellipsis characters to the same character
typographies_identical.each { |t| t.ellipsis_character = typography_ellipsis_character }
end
all_translations = typography_names.map{ |typography_name| @text_entries.collect{ |entry| entry.translations_with_typography(typography_name) }.flatten }.flatten
unicodes = all_translations.map(&:unicodes).flatten.uniq.sort
typographies_identical.each do |t|
fbc = t.fallback_character
fbcUnicode = 0
if fbc
if fbc.downcase == 'skip'
fbcUnicode = 0xFEFF
elsif fbc.length == 1
fbcUnicode = fbc[0].ord
else
begin
fbcUnicode = Integer(fbc.gsub(/\.0*$/,''))
rescue
fail "Please only specify one character or ('skip') as Fallback Character, typography \"#{typography_with_fallback_character.name}\" has Fallback Character \"#{typography_with_fallback_character.fallback_character}\""
end
end
unicodes += [ fbcUnicode ]
end
t.fallback_character = fbcUnicode
tec = t.ellipsis_character
tecUnicode = 0
if tec
if tec.length == 1
tecUnicode = tec[0].ord
else
begin
tecUnicode = Integer(tec.gsub(/\.0*$/,''))
rescue
fail "Please only specify one character as Ellipsis Character for typography \"#{typography_with_fallback_character.name}\""
end
end
unicodes += [ tecUnicode ]
end
t.ellipsis_character = tecUnicode
end
typographies_identical.each{ |t|
if t.wildcard_characters
t.wildcard_characters.to_s.split('').each { |c|
unicodes += [ c[0].ord ]
}
end
if t.wildcard_ranges
unicodes += decode_ranges(t.wildcard_ranges)
end
}
unicodes = convert_to_contextual_forms(unicodes)
unicodes = mirror_brackes(unicodes)
unicodes = add_thai(unicodes)
unicodes.delete(0x0002) # TouchGFX wildcard character
unicodes.delete(0x200B) # ZERO WIDTH SPACE
unicodes.delete(0xFEFF) # ZERO WIDTH NO-BREAK SPACE
unicodes = unicodes.uniq.sort
check_for_rtl(unicodes)
FileIO.write_file_silent(File.join(@output_directory, "UnicodeList#{@unique_typography.cpp_name}_#{@unique_typography.font_size}_#{@unique_typography.bpp}.txt"), unicodes.join(LINE_ENDINGS) )
end
end

View File

@ -0,0 +1,30 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
# All rights reserved.</center></h2>
#
# This software component is licensed by ST under Ultimate Liberty license
# SLA0044, the "License"; You may not use this file except in compliance with
# the License. You may obtain a copy of the License at:
# www.st.com/SLA0044
#
##############################################################################
class UnmappedDataFontCpp < Template
def input_path
File.join(root_dir,'Templates','UnmappedDataFont.cpp.temp')
end
def output_path
'/src/UnmappedDataFont.cpp'
end
def output_filename
File.join(@output_directory, output_path)
end
def run
if (!File::exists?(output_filename))
#generate UnmappedDataFont.cpp
super
end
end
end

View File

@ -0,0 +1,30 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
# All rights reserved.</center></h2>
#
# This software component is licensed by ST under Ultimate Liberty license
# SLA0044, the "License"; You may not use this file except in compliance with
# the License. You may obtain a copy of the License at:
# www.st.com/SLA0044
#
##############################################################################
class UnmappedDataFontHpp < Template
def input_path
File.join(root_dir,'Templates','UnmappedDataFont.hpp.temp')
end
def output_path
'/include/fonts/UnmappedDataFont.hpp'
end
def output_filename
File.join(@output_directory, output_path)
end
def run
if (!File::exists?(output_filename))
#generate GeneratedFont.hpp
super
end
end
end

View File

@ -0,0 +1,96 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
# All rights reserved.</center></h2>
#
# This software component is licensed by ST under Ultimate Liberty license
# SLA0044, the "License"; You may not use this file except in compliance with
# the License. You may obtain a copy of the License at:
# www.st.com/SLA0044
#
##############################################################################
require 'roo'
require 'lib/text_entries'
class ExcelRow
def initialize(excel_file, header, row_number, first_column)
@excel_file = excel_file
@header = header
@row_number = row_number
@first_column = first_column
end
def [](column_header)
value_at(@row_number, column_number(column_header.to_s))
end
def exists?(name)
!@header[name.to_s.downcase].nil?
end
private
def column_number(name)
column_index = @header[name.downcase]
raise "#{name} column not found in excel file" if column_index.nil?
column_index + @first_column
end
def value_at(row, col)
value = @excel_file.cell(row,col).to_s
if value.empty?
nil
else
check_encoding(value)
value
end
end
def check_encoding(value)
puts value if value.force_encoding("UTF-8").valid_encoding? == false
end
end
class ExcelReader
def initialize(file_name, sheet, header_row, first_column)
@excel_file = Roo::Excelx.new file_name
@sheet = sheet
@excel_file.default_sheet = sheet
@header_row = header_row
@first_column = first_column
@header = {}
header.each_with_index do |cell, ix|
@header[cell.downcase] = ix
end
end
def read_header
yield header
end
def read_rows
(@header_row + 1).upto(last_row_number) do |row_number|
yield row(row_number)
end
end
private
def last_row_number
@excel_file.last_row
end
def header
@excel_file.row(@header_row).compact.map(&:strip)
end
def row(row_number)
ExcelRow.new(@excel_file, @header, row_number, @first_column)
end
end

View File

@ -0,0 +1,32 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
# All rights reserved.</center></h2>
#
# This software component is licensed by ST under Ultimate Liberty license
# SLA0044, the "License"; You may not use this file except in compliance with
# the License. You may obtain a copy of the License at:
# www.st.com/SLA0044
#
##############################################################################
require 'rubygems'
require 'erb'
require 'fileutils'
require 'pathname'
class FileIO
def self.write_file(file_name, contents)
callingPath = Pathname.new($calling_path)
filePath = Pathname.new(file_name)
puts "Generating #{filePath.relative_path_from(callingPath)}"
write_file_silent(file_name, contents)
end
def self.write_file_silent(file_name, contents)
FileUtils.mkdir_p(File.dirname(file_name))
unless File.exist?(file_name) && contents == File.open(file_name, 'r') { |f| f.read() }
File.open(file_name, 'w') { |f| f.write(contents) }
end
end
end

View File

@ -0,0 +1,35 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
# All rights reserved.</center></h2>
#
# This software component is licensed by ST under Ultimate Liberty license
# SLA0044, the "License"; You may not use this file except in compliance with
# the License. You may obtain a copy of the License at:
# www.st.com/SLA0044
#
##############################################################################
require 'lib/text_entries_excel_reader'
require 'lib/typographies_excel_reader'
require 'lib/sanitizer'
require 'lib/string_collector'
require 'lib/outputter'
class Generator
def run(file_name, output_path, text_output_path, font_asset_path, data_format, remap_identical_texts, generate_binary_translations, generate_binary_fonts, framebuffer_bpp, generate_font_format)
#puts "Running TextEntriesExcelReader, #{Time.now.strftime("%H:%M:%S:%L")}"
text_entries = TextEntriesExcelReader.new(file_name).run
#puts "Running TypoEntriesExcelReader, #{Time.now.strftime("%H:%M:%S:%L")}"
typographies = TypographiesExcelReader.new(file_name).run
#puts "Running Sanitizer, #{Time.now.strftime("%H:%M:%S:%L")}"
Sanitizer.new(text_entries, typographies, framebuffer_bpp).run
#puts "Running StringCollector, #{Time.now.strftime("%H:%M:%S:%L")}"
if remap_identical_texts=='yes'
string_indices, characters = StringCollector.new(text_entries, typographies).run
end
#puts "Running Outputter, #{Time.now.strftime("%H:%M:%S:%L")}"
Outputter.new(string_indices, characters, text_entries, typographies, text_output_path, output_path, font_asset_path, data_format, remap_identical_texts, generate_binary_translations, generate_binary_fonts, generate_font_format).run
end
end

View File

@ -0,0 +1,90 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
# All rights reserved.</center></h2>
#
# This software component is licensed by ST under Ultimate Liberty license
# SLA0044, the "License"; You may not use this file except in compliance with
# the License. You may obtain a copy of the License at:
# www.st.com/SLA0044
#
##############################################################################
require 'lib/file_io'
require 'lib/emitters/template'
require 'lib/emitters/text_keys_and_languages_hpp'
require 'lib/emitters/texts_cpp'
require 'lib/emitters/languages_cpp'
require 'lib/emitters/languages_bin'
require 'lib/emitters/unicodes_txt'
require 'lib/emitters/fonts_cpp'
require 'lib/emitters/generated_font_cpp'
require 'lib/emitters/generated_font_hpp'
require 'lib/emitters/unmapped_data_font_cpp'
require 'lib/emitters/unmapped_data_font_hpp'
require 'lib/emitters/cached_font_cpp'
require 'lib/emitters/cached_font_hpp'
require 'lib/emitters/font_cache_cpp'
require 'lib/emitters/font_cache_hpp'
require 'lib/emitters/application_font_provider_hpp'
require 'lib/emitters/application_font_provider_cpp'
require 'lib/emitters/typed_text_database_hpp'
require 'lib/emitters/typed_text_database_cpp'
class Outputter
def initialize(string_indices, characters, text_entries, typographies, localization_output_directory, fonts_output_directory, font_asset_path, data_format, remap_identical_texts, generate_binary_translations, generate_binary_fonts, generate_font_format)
@string_indices = string_indices #dictionary of all string indices into the characters array
@characters = characters #one array of the needed strings in optimal order
@text_entries = text_entries
@typographies = typographies
@localization_output_directory = localization_output_directory
@fonts_output_directory = fonts_output_directory
@font_asset_path = font_asset_path
@data_format = data_format
@remap_identical_texts = remap_identical_texts
@generate_binary_translations = generate_binary_translations
@generate_binary_fonts = generate_binary_fonts
@generate_font_format = generate_font_format
end
def run
#puts "Running Outputter1, #{Time.now.strftime("%H:%M:%S:%L")}"
[ GeneratedFontHpp,
GeneratedFontCpp,
UnmappedDataFontHpp,
UnmappedDataFontCpp,
CachedFontHpp,
CachedFontCpp,
FontCacheHpp,
FontCacheCpp,
UnicodesTxt ].each { |template| template.new(@text_entries, @typographies, @fonts_output_directory).run }
[ ApplicationFontProviderCpp,
ApplicationFontProviderHpp ].each { |template| template.new(@text_entries, @typographies, @fonts_output_directory, @generate_font_format).run }
#puts "Running Outputter2, #{Time.now.strftime("%H:%M:%S:%L")}"
[ TextKeysAndLanguages,
TypedTextDatabaseHpp].each { |template| template.new(@text_entries, @typographies, @localization_output_directory).run }
#puts "Running Outputter3, #{Time.now.strftime("%H:%M:%S:%L")}"
TypedTextDatabaseCpp.new(@text_entries, @typographies, @localization_output_directory, @generate_binary_translations, @generate_font_format).run
#puts "Running Outputter4, #{Time.now.strftime("%H:%M:%S:%L")}"
TextsCpp.new(@characters, @text_entries, @typographies, @localization_output_directory, @remap_identical_texts, @generate_binary_translations).run
#puts "Running Outputter5, #{Time.now.strftime("%H:%M:%S:%L")}"
LanguagesCpp.new(@string_indices, @text_entries, @localization_output_directory, @remap_identical_texts, @generate_binary_translations).run
#puts "Running Outputter6, #{Time.now.strftime("%H:%M:%S:%L")}"
FontsCpp.new(@text_entries, @typographies, @fonts_output_directory, @font_asset_path, @data_format, @generate_binary_fonts, @generate_font_format).run
if @generate_binary_translations.downcase == 'yes'
#puts "Running Outputter7, #{Time.now.strftime("%H:%M:%S:%L")}"
[ LanguagesBin ].each { |template| template.new(@text_entries, @typographies, @localization_output_directory).run }
end
#puts "Done Outputter, #{Time.now.strftime("%H:%M:%S:%L")}"
end
end

View File

@ -0,0 +1,189 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
# All rights reserved.</center></h2>
#
# This software component is licensed by ST under Ultimate Liberty license
# SLA0044, the "License"; You may not use this file except in compliance with
# the License. You may obtain a copy of the License at:
# www.st.com/SLA0044
#
##############################################################################
TextEntrySanitizer = Struct.new(:text_entries, :typographies, :framebuffer_bpp)
$warning_prefix = "\nWARNING (TextConverter): "
class Sanitizer < TextEntrySanitizer
def run
[ RemoveDuplicateKeys,
RemoveIncompleteLanguages,
RemoveKeysWithMoreThanTwoSubstitutions,
RemoveKeysWithDifferentNumberOfSubstitutions,
RemoveTextEntriesWithInvalidTypography,
RemoveTextEntriesWithInvalidAlignment,
RemoveTextEntriesWithInvalidDirection,
CheckSizeAndBpp,
DowngradeFontsBitDepth
].each do |sanitizer|
sanitizer.new(text_entries, typographies, framebuffer_bpp).run
end
end
end
class RemoveDuplicateKeys < TextEntrySanitizer
def run
# puts "Removing duplicate text ids"
counts = Hash.new(0)
counts = text_entries.inject(Hash.new(0)) do |h, entry|
h[entry.cpp_text_id.upcase] = h[entry.cpp_text_id.upcase] + 1
h
end
text_entries.each do |text_entry|
if counts[text_entry.cpp_text_id.upcase] > 1
raise "#{$warning_prefix} Duplicate key removed: #{text_entry.text_id}, yields cpp identifier #{text_entry.cpp_text_id.upcase}"
text_entries.remove(text_entry)
end
end
end
end
class RemoveIncompleteLanguages < TextEntrySanitizer
def run
# puts "Removing incomplete languages"
languages = text_entries.languages
languages.each do |language|
text_entries_with_missing_translations = text_entries.select do |text_entry|
text_entry.translation_in(language).empty?
end
text_entries_with_missing_translations.each do |text_entry|
raise "#{$warning_prefix} Language #{language} is missing translation for #{text_entry.text_id}"
end
if text_entries_with_missing_translations.any?
text_entries.remove_language(language)
end
end
end
end
class RemoveKeysWithMoreThanTwoSubstitutions < TextEntrySanitizer
def run
# puts "Removing text entries with more than two substitutions"
text_entries.languages.each do |language|
text_entries_with_more_than_two_substitutions = text_entries.select do |text_entry|
text_entry.number_of_substitutions_in(language) > 2
end
text_entries_with_more_than_two_substitutions.each do |text_entry|
raise "#{$warning_prefix} Text id #{text_entry.text_id} has #{text_entry.number_of_substitutions_in(language)} substitutions"
#text_entries.remove(text_entry)
end
end
end
end
class RemoveKeysWithDifferentNumberOfSubstitutions < TextEntrySanitizer
def run
# puts "Removing text entries with different number of substitutions"
text_entries.each do |text_entry|
translations = text_entry.translations
number_of_substitutions_per_translation = translations.collect { |translation| translation.number_of_substitutions }
if number_of_substitutions_per_translation.uniq.count > 1
raise "#{$warning_prefix} Text id #{text_entry.text_id} has different number of substitutions for some languages"
#text_entries.remove(text_entry)
end
end
end
end
class RemoveTextEntriesWithInvalidTypography < TextEntrySanitizer
def run
# puts "Removing text entries referring to non existing typographies"
text_entries.each do |text_entry|
non_existing_typographies = (text_entry.get_all_typographies - typographies.map( &:name )).compact;
if non_existing_typographies.any?
raise "#{$warning_prefix} Text id #{text_entry.text_id} uses unknown typographies #{non_existing_typographies}"
#text_entries.remove(text_entry)
end
end
end
end
class RemoveTextEntriesWithInvalidAlignment < TextEntrySanitizer
def run
# puts "Removing text entries referring to invalid alignment"
text_entries.each do |text_entry|
alignments = text_entry.get_all_alignments_as_string
illegal_alignments = alignments.select { |a| !['LEFT', 'RIGHT', 'CENTER'].include?(a) }
if illegal_alignments.any?
raise "#{$warning_prefix} Text id #{text_entry.text_id} uses unknown alignments #{illegal_alignments}"
#text_entries.remove(text_entry)
end
end
end
end
class RemoveTextEntriesWithInvalidDirection < TextEntrySanitizer
def run
# puts "Removing text entries referring to invalid direction"
text_entries.each do |text_entry|
directions = text_entry.get_all_directions_as_string
illegal_directions = directions.select { |d| !['LTR', 'RTL'].include?(d) }
if illegal_directions.any?
raise "#{$warning_prefix} Text id #{text_entry.text_id} uses unknown directions #{illegal_directions}"
#text_entries.remove(text_entry)
end
end
end
end
class CheckSizeAndBpp < TextEntrySanitizer
def run
# puts "Raise an error if typography size or bpp does have sane values"
typographies.each do |typography|
if (not [1, 2, 4, 8].include?(typography.bpp))
raise "#{$warning_prefix} Typography named '#{typography.name}' has bpp value '#{typography.bpp}', which is not a valid value"
end
if ( (not typography.font_size.integer?) or (typography.font_size < 1) )
raise "#{$warning_prefix} Typography named '#{typography.name}' has font size value '#{typography.font_size}', which is not a valid value"
end
end
end
end
class DowngradeFontsBitDepth < TextEntrySanitizer
def run
if (not framebuffer_bpp.nil?)
m = framebuffer_bpp.match(/BPP(\d+)/)
bpp = m.nil? ? 24 : m[1].to_i
typographies.each do |typography|
case bpp
when 8
if typography.bpp > 2
puts "Downgrading typography #{typography.name} from #{typography.bpp.to_s}bpp to 2bpp"
typography.bpp = 2
end
when 4
if typography.bpp > 4
puts "Downgrading typography #{typography.name} from #{typography.bpp.to_s}bpp to 4bpp"
typography.bpp = 4
end
when 2
if typography.bpp > 2
puts "Downgrading typography #{typography.name} from #{typography.bpp.to_s}bpp to 2bpp"
typography.bpp = 2
end
when 1
if typography.bpp > 1
puts "Downgrading typography #{typography.name} from #{typography.bpp.to_s}bpp to 1bpp"
typography.bpp = 1
end
end
end
end
end
end

View File

@ -0,0 +1,59 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
# All rights reserved.</center></h2>
#
# This software component is licensed by ST under Ultimate Liberty license
# SLA0044, the "License"; You may not use this file except in compliance with
# the License. You may obtain a copy of the License at:
# www.st.com/SLA0044
#
##############################################################################
CollectorStruct = Struct.new(:text_entries, :typographies)
$warning_prefix = "\nWARNING (TextConverter): "
class StringCollector < CollectorStruct
def run
string_indices = {}
characters = Array.new
#collect all strings for sorting
all_strings = Array.new
text_entries.each do |text_entry|
text_entry.translations.each do |translation|
all_strings.push(translation)
end
end
#sort by length
all_strings.sort_by!(){|x| -x.length}
#collect all string indeces, and add to characters array
all_strings.each do |translation|
#lookup translation in hash
#if not found, add to characters and insert index in hash for translation and all suffices
#if found, do nothing
unicodes = translation.unicodes
index = string_indices[unicodes]
if not index
new_index = characters.length
#puts "new string: #{translation.to_cpp} index: #{new_index}"
characters.concat(unicodes).push(0)
for start in 0 .. unicodes.length-1
sub_string = unicodes[start..-1]
# if the substring is present, all shorter substrings are also present, so do not add again
break if string_indices[sub_string]
string_indices[sub_string] = (new_index + start)
end
else
#puts "existing string: #{translation.to_cpp} index: #{index}"
end
end
#puts characters.inject("") {|t,i| "#{t}#{i==0?'|' : i.chr}"}
#puts "Total: #{characters.length} chars"
#puts string_indices
[string_indices, characters]
end
end

View File

@ -0,0 +1,270 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
# All rights reserved.</center></h2>
#
# This software component is licensed by ST under Ultimate Liberty license
# SLA0044, the "License"; You may not use this file except in compliance with
# the License. You may obtain a copy of the License at:
# www.st.com/SLA0044
#
##############################################################################
class TextEntries
include Enumerable
def initialize
@entries = []
@is_rtl = false
@unicode_is_rtl = false
end
def each(&block)
@entries.each(&block)
end
def remove(entry)
@entries.delete(entry)
end
def add(entry)
@entries.push(entry)
end
def empty?
@entries.empty?
end
def different_typographies
[ar,default]
end
def different_alignments
[ar,default]
end
def languages
if @entries.empty?
[]
else
@entries.first.languages
end
end
def remove_language(language)
@entries.each { |entry| entry.remove_translation_in(language) }
end
def typographies
@entries.map { |entry| entry.typography }.uniq
end
def entries
@entries
end
def with_typography(typography)
@entries.select { |entry| entry.typography == typography }
end
def include?(text_entry)
@entries.find { |entry| entry.text_id == text_entry.text_id || entry.cpp_text_id == text_entry.cpp_text_id }
end
def unicode_uses_rtl
@unicode_is_rtl = true
end
def is_rtl
@unicode_is_rtl || @entries.any? { |entry| entry.is_rtl }
end
end
class TextEntry
attr_reader :text_id
attr_reader :typography
attr_reader :typographies
attr_reader :alignments
attr_reader :directions
def initialize(text_id, typography, alignment, direction)
@text_id = text_id
@typographies = {}
@alignments = {}
@directions = {}
@translations = {}
# default typography
@typography = typography
# default alignment
@alignment = alignment
# default direction
@direction = get_direction_as_string(direction)
@right_to_left = false
end
def add_typography(language, typography)
@typographies[language] = typography
end
def add_alignment(language, alignment)
@alignments[language] = alignment
end
def add_direction(language, direction)
@directions[language] = direction
end
def add_translation(language, text)
translation = Translation.new(text)
@translations[language] = translation
end
def remove_translation_in(language)
@translations.delete(language)
end
def translations
@translations.values
end
def translation_in(language)
@translations[language]
end
def translations_with_typography(typography)
languages_with_typography = languages.select do |language|
if @typographies[language].nil?
@typography == typography
else
@typographies[language] == typography
end
end
languages_with_typography.collect{ |language| translation_in(language) }
end
def languages
@translations.keys
end
def number_of_substitutions_in(language)
@translations[language].number_of_substitutions
end
def cpp_text_id
cppify(text_id)
end
def alignment
get_alignment_as_string(@alignment)
end
def direction
get_direction_as_string(@direction)
end
# includes the default typography
def get_all_typographies
@typographies.values.compact.insert(0, @typography)
end
# includes the default alignment
def get_all_alignments_as_string
@alignments.values.compact.collect{ |a| get_alignment_as_string(a) }.insert(0, alignment)
end
# includes the default direction
def get_all_directions_as_string
@directions.values.compact.collect{ |a| get_direction_as_string(a) }.insert(0, direction)
end
def is_rtl
@is_rtl
end
private
def get_alignment_as_string(a)
case a.to_s.downcase
when 'right'
'RIGHT'
when 'center'
'CENTER'
when 'left', ''
'LEFT'
else
a.to_s
end
end
def get_direction_as_string(d)
case d.to_s.downcase
when 'ltr', ''
'LTR'
when 'rtl'
@is_rtl = true
'RTL'
else
d.to_s
end
end
def cppify(text)
t_type = "T_" + text
# strip the keys for characters, that can not be used in C++
t_type = t_type.to_ascii
t_type.gsub!(" ", "_")
t_type.gsub!(")", "")
t_type.gsub!("(", "")
t_type.gsub!("-", "")
t_type.gsub!("\"", "")
t_type.gsub!("/", "")
t_type.gsub!(".", "")
t_type
end
end
class Translation
def initialize(text)
@text = text
end
def empty?
@text.nil? || @text.empty?
end
def length
@text.length
end
def number_of_substitutions
to_cpp.count("\2")
end
def unicodes
@unicodes ||=
begin
numbers.map { |number| number.to_s.gsub(/\[|\]/,'').to_i }
end
end
def to_cpp
cpp_text = @text.gsub("\2", '') # Remove all existing placeholders
regex = Regexp.new(/([^\\]|^)<(|.*?[^\\])>/) # Avoid matching \< and \>
while cpp_text.match(regex)
cpp_text.gsub!(regex, '\1'+"\2")
end
cpp_text.gsub('\\<', '<').gsub('\\>', '>') # Remove \ before < and >
end
private
def numbers
to_cpp.unpack('U*')
end
end
class String
def to_ascii
# modernized version of http://craigjolicoeur.com/blog/ruby-iconv-to-the-rescue
self.encode("ASCII", "UTF-8", :undef => :replace, :invalid => :replace, :replace => '').
unpack('U*').select { |cp| cp < 127 }.pack('U*')
end
end

View File

@ -0,0 +1,129 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
# All rights reserved.</center></h2>
#
# This software component is licensed by ST under Ultimate Liberty license
# SLA0044, the "License"; You may not use this file except in compliance with
# the License. You may obtain a copy of the License at:
# www.st.com/SLA0044
#
##############################################################################
require 'lib/excel_reader'
class TextEntriesExcelReader
attr_reader :reader
def initialize(file_name)
#puts "Running TextEntriesExcelReader:init, #{Time.now.strftime("%H:%M:%S:%L")}"
header_row_number = 3
header_column_number = 2
@reader = ExcelReader.new(file_name, "Translation", header_row_number, header_column_number)
@text_entries = TextEntries.new
end
def run
#puts "Running TextEntriesExcelReader:run, #{Time.now.strftime("%H:%M:%S:%L")}"
reader.read_header do |header|
@alignments = header.select { |column| column.match(/^.*-ALIGNMENT$/i) }.map(&:capitalize)
@directions = header.select { |column| column.match(/^.*-DIRECTION$/i) }.map(&:capitalize)
@typographies = header.select { |column| column.match(/^.*-TYPOGRAPHY$/i) }.map(&:capitalize)
@languages = header.select { |column| column.match(/^(\w{1,3})$/i ) }.map(&:capitalize)
end
# Check for undefined languages in language specific typographies
# Any undefined language specific typographies are removed
@typographies.select! do |typography|
language, _ = typography.split('-')
if not @languages.include?(language)
raise "#{$warning_prefix} Unknown language in column #{language}-TYPOGRAPHY"
end
@languages.include?(language)
end
# Check for undefined languages in language specific alignments
# Any undefined language specific alignments are removed
@alignments.select! do |alignment|
language, _ = alignment.split('-')
if not @languages.include?(language)
raise "#{$warning_prefix} Unknown language in column #{language}-ALIGNMENT"
end
@languages.include?(language)
end
# Check for undefined languages in language specific directions
# Any undefined language specific directions are removed
@directions.select! do |direction|
language, _ = direction.split('-')
if not @languages.include?(language)
raise "#{$warning_prefix} Unknown language in column #{language}-DIRECTION"
end
@languages.include?(language)
end
reader.read_rows do |row|
text_id = row[:"Text ID"]
default_typography = row[:"Typography Name"]
default_alignment = row[:Alignment]
if row.exists?(:Direction)
default_direction = row[:Direction]
end
text_id = text_id.strip if text_id
default_typography = default_typography.strip if default_typography
default_alignment = default_alignment.strip if default_alignment
default_direction = default_direction.strip if default_direction
if text_id && default_typography
unless text_id.match(/^([0-9a-zA-Z_])*$/)
puts "Illegal characters found in Text ID '#{text_id}'"
fail
end
text_entry = TextEntry.new(text_id, default_typography, default_alignment, default_direction)
@typographies.each do |typography|
language, _ = typography.split('-')
#puts "adding typography #{typography}"
t = row[typography]
t = t.strip if t
text_entry.add_typography(language, t)
end
@alignments.each do |alignment|
language, _ = alignment.split('-')
#puts "adding alignment #{alignment}"
a = row[alignment]
a = a.strip if a
text_entry.add_alignment(language, a)
end
@directions.each do |direction|
language, _ = direction.split('-')
#puts "adding direction #{direction}"
d = row[direction]
d = d.strip if d
text_entry.add_direction(language, d)
end
@languages.each do |language|
#puts "adding language #{language}"
# Do *not* strip leading/trailing whitespace from translations.
text_entry.add_translation(language, row[language])
end
@text_entries.add(text_entry)
end
end
@text_entries
end
end

View File

@ -0,0 +1,18 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
# All rights reserved.</center></h2>
#
# This software component is licensed by ST under Ultimate Liberty license
# SLA0044, the "License"; You may not use this file except in compliance with
# the License. You may obtain a copy of the License at:
# www.st.com/SLA0044
#
##############################################################################
class Typography < Struct.new(:name, :font_file, :font_size, :bpp, :fallback_character, :ellipsis_character, :wildcard_characters, :wildcard_ranges)
def cpp_name
font_file.gsub(/\.ttf$/,"").gsub(/[^0-9a-zA-Z]/, "_")
end
end

View File

@ -0,0 +1,73 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
# All rights reserved.</center></h2>
#
# This software component is licensed by ST under Ultimate Liberty license
# SLA0044, the "License"; You may not use this file except in compliance with
# the License. You may obtain a copy of the License at:
# www.st.com/SLA0044
#
##############################################################################
require 'lib/excel_reader'
require 'lib/typographies'
class TypographiesExcelReader
attr_reader :reader
def initialize(file_name)
header_row_number = 3
header_column_number = 2
@reader = ExcelReader.new(file_name, 'Typography', header_row_number, header_column_number)
@typographies = []
end
def run
reader.read_rows do |row|
name = row[:'Typography Name']
font = row[:font]
size = row[:size]
bpp = row[:bpp]
if row.exists?(:'Fallback Character')
fallback_character = row[:'Fallback Character']
end
if row.exists?(:'Wildcard Characters')
wildcard_characters = row[:'Wildcard Characters']
end
if row.exists?(:'Widget Wildcard Characters')
wildcard_characters ||= '' # Make sure wc_chars is defined
wildcard_characters += (row[:'Widget Wildcard Characters'] || '')
end
if row.exists?(:'Character Ranges') # New name
wildcard_ranges = row[:'Character Ranges']
elsif row.exists?(:'Wildcard Ranges') # Old name
wildcard_ranges = row[:'Wildcard Ranges']
end
if row.exists?(:'Ellipsis Character')
ellipsis_character = row[:'Ellipsis Character']
end
if name
name = name.strip
unless name.match(/^([0-9a-zA-Z_])*$/)
fail "Illegal characters found in Text ID '#{name}'"
end
end
font = font.strip if font
size = size.strip if size
bpp = bpp.strip if bpp
fallback_character = fallback_character.strip if fallback_character
wildcard_characters = wildcard_characters.strip if wildcard_characters
wildcard_ranges = wildcard_ranges.strip if wildcard_ranges
ellipsis_character = ellipsis_character.strip if ellipsis_character
if name && font && size && bpp
@typographies.push Typography.new(name, font, size.to_i, bpp.to_i, fallback_character, ellipsis_character, wildcard_characters, wildcard_ranges)
end
end
@typographies
end
end