diff options
Diffstat (limited to 'gfx/graphite2/src/NameTable.cpp')
-rw-r--r-- | gfx/graphite2/src/NameTable.cpp | 254 |
1 files changed, 254 insertions, 0 deletions
diff --git a/gfx/graphite2/src/NameTable.cpp b/gfx/graphite2/src/NameTable.cpp new file mode 100644 index 0000000000..d42b7f95bd --- /dev/null +++ b/gfx/graphite2/src/NameTable.cpp @@ -0,0 +1,254 @@ +/* GRAPHITE2 LICENSING + + Copyright 2010, SIL International + All rights reserved. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should also have received a copy of the GNU Lesser General Public + License along with this library in the file named "LICENSE". + If not, write to the Free Software Foundation, 51 Franklin Street, + Suite 500, Boston, MA 02110-1335, USA or visit their web page on the + internet at http://www.fsf.org/licenses/lgpl.html. + +Alternatively, the contents of this file may be used under the terms of the +Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public +License, as published by the Free Software Foundation, either version 2 +of the License or (at your option) any later version. +*/ +#include "inc/Main.h" +#include "inc/Endian.h" + +#include "inc/NameTable.h" +#include "inc/UtfCodec.h" + +using namespace graphite2; + +NameTable::NameTable(const void* data, size_t length, uint16 platformId, uint16 encodingID) + : m_platformId(0), m_encodingId(0), m_languageCount(0), + m_platformOffset(0), m_platformLastRecord(0), m_nameDataLength(0), + m_table(0), m_nameData(NULL) +{ + void *pdata = gralloc<byte>(length); + if (!pdata) return; + memcpy(pdata, data, length); + m_table = reinterpret_cast<const TtfUtil::Sfnt::FontNames*>(pdata); + + if ((length > sizeof(TtfUtil::Sfnt::FontNames)) && + (length > sizeof(TtfUtil::Sfnt::FontNames) + + sizeof(TtfUtil::Sfnt::NameRecord) * ( be::swap<uint16>(m_table->count) - 1))) + { + uint16 offset = be::swap<uint16>(m_table->string_offset); + if (offset < length) + { + m_nameData = reinterpret_cast<const uint8*>(pdata) + offset; + setPlatformEncoding(platformId, encodingID); + m_nameDataLength = uint16(length - offset); + return; + } + } + free(const_cast<TtfUtil::Sfnt::FontNames*>(m_table)); + m_table = NULL; +} + +uint16 NameTable::setPlatformEncoding(uint16 platformId, uint16 encodingID) +{ + if (!m_nameData) return 0; + uint16 i = 0; + uint16 count = be::swap<uint16>(m_table->count); + for (; i < count; i++) + { + if (be::swap<uint16>(m_table->name_record[i].platform_id) == platformId && + be::swap<uint16>(m_table->name_record[i].platform_specific_id) == encodingID) + { + m_platformOffset = i; + break; + } + } + while ((++i < count) && + (be::swap<uint16>(m_table->name_record[i].platform_id) == platformId) && + (be::swap<uint16>(m_table->name_record[i].platform_specific_id) == encodingID)) + { + m_platformLastRecord = i; + } + m_encodingId = encodingID; + m_platformId = platformId; + return 0; +} + +void* NameTable::getName(uint16& languageId, uint16 nameId, gr_encform enc, uint32& length) +{ + uint16 anyLang = 0; + uint16 enUSLang = 0; + uint16 bestLang = 0; + if (!m_table) + { + languageId = 0; + length = 0; + return NULL; + } + for (uint16 i = m_platformOffset; i <= m_platformLastRecord; i++) + { + if (be::swap<uint16>(m_table->name_record[i].name_id) == nameId) + { + uint16 langId = be::swap<uint16>(m_table->name_record[i].language_id); + if (langId == languageId) + { + bestLang = i; + break; + } + // MS language tags have the language in the lower byte, region in the higher + else if ((langId & 0xFF) == (languageId & 0xFF)) + { + bestLang = i; + } + else if (langId == 0x409) + { + enUSLang = i; + } + else + { + anyLang = i; + } + } + } + if (!bestLang) + { + if (enUSLang) bestLang = enUSLang; + else + { + bestLang = anyLang; + if (!anyLang) + { + languageId = 0; + length = 0; + return NULL; + } + } + } + const TtfUtil::Sfnt::NameRecord & nameRecord = m_table->name_record[bestLang]; + languageId = be::swap<uint16>(nameRecord.language_id); + uint16 utf16Length = be::swap<uint16>(nameRecord.length); + uint16 offset = be::swap<uint16>(nameRecord.offset); + if(offset + utf16Length > m_nameDataLength) + { + languageId = 0; + length = 0; + return NULL; + } + utf16Length >>= 1; // in utf16 units + utf16::codeunit_t * utf16Name = gralloc<utf16::codeunit_t>(utf16Length + 1); + if (!utf16Name) + { + languageId = 0; + length = 0; + return NULL; + } + const uint8* pName = m_nameData + offset; + for (size_t i = 0; i < utf16Length; i++) + { + utf16Name[i] = be::read<uint16>(pName); + } + utf16Name[utf16Length] = 0; + if (!utf16::validate(utf16Name, utf16Name + utf16Length)) + { + free(utf16Name); + languageId = 0; + length = 0; + return NULL; + } + switch (enc) + { + case gr_utf8: + { + utf8::codeunit_t* uniBuffer = gralloc<utf8::codeunit_t>(3 * utf16Length + 1); + if (!uniBuffer) + { + free(utf16Name); + languageId = 0; + length = 0; + return NULL; + } + utf8::iterator d = uniBuffer; + for (utf16::const_iterator s = utf16Name, e = utf16Name + utf16Length; s != e; ++s, ++d) + *d = *s; + length = uint32(d - uniBuffer); + uniBuffer[length] = 0; + free(utf16Name); + return uniBuffer; + } + case gr_utf16: + length = utf16Length; + return utf16Name; + case gr_utf32: + { + utf32::codeunit_t * uniBuffer = gralloc<utf32::codeunit_t>(utf16Length + 1); + if (!uniBuffer) + { + free(utf16Name); + languageId = 0; + length = 0; + return NULL; + } + utf32::iterator d = uniBuffer; + for (utf16::const_iterator s = utf16Name, e = utf16Name + utf16Length; s != e; ++s, ++d) + *d = *s; + length = uint32(d - uniBuffer); + uniBuffer[length] = 0; + free(utf16Name); + return uniBuffer; + } + } + free(utf16Name); + languageId = 0; + length = 0; + return NULL; +} + +uint16 NameTable::getLanguageId(const char * bcp47Locale) +{ + size_t localeLength = strlen(bcp47Locale); + uint16 localeId = m_locale2Lang.getMsId(bcp47Locale); + if (m_table && (be::swap<uint16>(m_table->format) == 1)) + { + const uint8 * pLangEntries = reinterpret_cast<const uint8*>(m_table) + + sizeof(TtfUtil::Sfnt::FontNames) + + sizeof(TtfUtil::Sfnt::NameRecord) * ( be::swap<uint16>(m_table->count) - 1); + uint16 numLangEntries = be::read<uint16>(pLangEntries); + const TtfUtil::Sfnt::LangTagRecord * langTag = + reinterpret_cast<const TtfUtil::Sfnt::LangTagRecord*>(pLangEntries); + if (pLangEntries + numLangEntries * sizeof(TtfUtil::Sfnt::LangTagRecord) <= m_nameData) + { + for (uint16 i = 0; i < numLangEntries; i++) + { + uint16 offset = be::swap<uint16>(langTag[i].offset); + uint16 length = be::swap<uint16>(langTag[i].length); + if ((offset + length <= m_nameDataLength) && (length == 2 * localeLength)) + { + const uint8* pName = m_nameData + offset; + bool match = true; + for (size_t j = 0; j < localeLength; j++) + { + uint16 code = be::read<uint16>(pName); + if ((code > 0x7F) || (code != bcp47Locale[j])) + { + match = false; + break; + } + } + if (match) + return 0x8000 + i; + } + } + } + } + return localeId; +} |