gfx/graphite2/src/NameTable.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /*  GRAPHITE2 LICENSING
     3     Copyright 2010, SIL International
     4     All rights reserved.
     6     This library is free software; you can redistribute it and/or modify
     7     it under the terms of the GNU Lesser General Public License as published
     8     by the Free Software Foundation; either version 2.1 of License, or
     9     (at your option) any later version.
    11     This program is distributed in the hope that it will be useful,
    12     but WITHOUT ANY WARRANTY; without even the implied warranty of
    13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    14     Lesser General Public License for more details.
    16     You should also have received a copy of the GNU Lesser General Public
    17     License along with this library in the file named "LICENSE".
    18     If not, write to the Free Software Foundation, 51 Franklin Street,
    19     Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
    20     internet at http://www.fsf.org/licenses/lgpl.html.
    22 Alternatively, the contents of this file may be used under the terms of the
    23 Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
    24 License, as published by the Free Software Foundation, either version 2
    25 of the License or (at your option) any later version.
    26 */
    27 #include "inc/Main.h"
    28 #include "inc/Endian.h"
    30 #include "inc/NameTable.h"
    31 #include "inc/UtfCodec.h"
    33 using namespace graphite2;
    35 NameTable::NameTable(const void* data, size_t length, uint16 platformId, uint16 encodingID)
    36  : m_platformId(0), m_encodingId(0), m_languageCount(0),
    37    m_platformOffset(0), m_platformLastRecord(0), m_nameDataLength(0),
    38    m_table(0), m_nameData(NULL)
    39 {
    40     void *pdata = gralloc<byte>(length);
    41     if (!pdata) return;
    42     memcpy(pdata, data, length);
    43     m_table = reinterpret_cast<const TtfUtil::Sfnt::FontNames*>(pdata);
    45     if ((length > sizeof(TtfUtil::Sfnt::FontNames)) &&
    46         (length > sizeof(TtfUtil::Sfnt::FontNames) +
    47          sizeof(TtfUtil::Sfnt::NameRecord) * ( be::swap<uint16>(m_table->count) - 1)))
    48     {
    49         uint16 offset = be::swap<uint16>(m_table->string_offset);
    50         m_nameData = reinterpret_cast<const uint8*>(pdata) + offset;
    51         setPlatformEncoding(platformId, encodingID);
    52         m_nameDataLength = length - offset;
    53     }
    54     else
    55     {
    56         free(const_cast<TtfUtil::Sfnt::FontNames*>(m_table));
    57         m_table = NULL;
    58     }
    59 }
    61 uint16 NameTable::setPlatformEncoding(uint16 platformId, uint16 encodingID)
    62 {
    63     if (!m_nameData) return 0;
    64     uint16 i = 0;
    65     uint16 count = be::swap<uint16>(m_table->count);
    66     for (; i < count; i++)
    67     {
    68         if (be::swap<uint16>(m_table->name_record[i].platform_id) == platformId &&
    69             be::swap<uint16>(m_table->name_record[i].platform_specific_id) == encodingID)
    70         {
    71             m_platformOffset = i;
    72             break;
    73         }
    74     }
    75     while ((++i < count) &&
    76            (be::swap<uint16>(m_table->name_record[i].platform_id) == platformId) &&
    77            (be::swap<uint16>(m_table->name_record[i].platform_specific_id) == encodingID))
    78     {
    79         m_platformLastRecord = i;
    80     }
    81     m_encodingId = encodingID;
    82     m_platformId = platformId;
    83     return 0;
    84 }
    86 void* NameTable::getName(uint16& languageId, uint16 nameId, gr_encform enc, uint32& length)
    87 {
    88     uint16 anyLang = 0;
    89     uint16 enUSLang = 0;
    90     uint16 bestLang = 0;
    91     if (!m_table)
    92     {
    93         languageId = 0;
    94         length = 0;
    95         return NULL;
    96     }
    97     for (uint16 i = m_platformOffset; i <= m_platformLastRecord; i++)
    98     {
    99         if (be::swap<uint16>(m_table->name_record[i].name_id) == nameId)
   100         {
   101             uint16 langId = be::swap<uint16>(m_table->name_record[i].language_id);
   102             if (langId == languageId)
   103             {
   104                 bestLang = i;
   105                 break;
   106             }
   107             // MS language tags have the language in the lower byte, region in the higher
   108             else if ((langId & 0xFF) == (languageId & 0xFF))
   109             {
   110                 bestLang = i;
   111             }
   112             else if (langId == 0x409)
   113             {
   114                 enUSLang = i;
   115             }
   116             else
   117             {
   118                 anyLang = i;
   119             }
   120         }
   121     }
   122     if (!bestLang)
   123     {
   124         if (enUSLang) bestLang = enUSLang;
   125         else
   126         {
   127             bestLang = anyLang;
   128             if (!anyLang)
   129             {
   130                 languageId = 0;
   131                 length = 0;
   132                 return NULL;
   133             }
   134         }
   135     }
   136     const TtfUtil::Sfnt::NameRecord & nameRecord = m_table->name_record[bestLang];
   137     languageId = be::swap<uint16>(nameRecord.language_id);
   138     uint16 utf16Length = be::swap<uint16>(nameRecord.length);
   139     uint16 offset = be::swap<uint16>(nameRecord.offset);
   140     if(offset + utf16Length > m_nameDataLength)
   141     {
   142         languageId = 0;
   143         length = 0;
   144         return NULL;
   145     }
   146     utf16Length >>= 1; // in utf16 units
   147     utf16::codeunit_t * utf16Name = gralloc<utf16::codeunit_t>(utf16Length);
   148     if (!utf16Name)
   149     {
   150         languageId = 0;
   151         length = 0;
   152         return NULL;
   153     }
   154     const uint8* pName = m_nameData + offset;
   155     for (size_t i = 0; i < utf16Length; i++)
   156     {
   157         utf16Name[i] = be::read<uint16>(pName);
   158     }
   159     switch (enc)
   160     {
   161     case gr_utf8:
   162     {
   163         utf8::codeunit_t* uniBuffer = gralloc<utf8::codeunit_t>(3 * utf16Length + 1);
   164         if (!uniBuffer)
   165         {
   166             free(utf16Name);
   167             languageId = 0;
   168             length = 0;
   169             return NULL;
   170         }
   171         utf8::iterator d = uniBuffer;
   172         for (utf16::const_iterator s = utf16Name, e = utf16Name + utf16Length; s != e; ++s, ++d)
   173             *d = *s;
   174         length = d - uniBuffer;
   175         uniBuffer[length] = 0;
   176         free(utf16Name);
   177         return uniBuffer;
   178     }
   179     case gr_utf16:
   180         length = utf16Length;
   181         return utf16Name;
   182     case gr_utf32:
   183     {
   184         utf32::codeunit_t * uniBuffer = gralloc<utf32::codeunit_t>(utf16Length  + 1);
   185         if (!uniBuffer)
   186         {
   187             free(utf16Name);
   188             languageId = 0;
   189             length = 0;
   190             return NULL;
   191         }
   192         utf32::iterator d = uniBuffer;
   193         for (utf16::const_iterator s = utf16Name, e = utf16Name + utf16Length; s != e; ++s, ++d)
   194             *d = *s;
   195         length = d - uniBuffer;
   196         uniBuffer[length] = 0;
   197         free(utf16Name);
   198         return uniBuffer;
   199     }
   200     }
   201     free(utf16Name);
   202     languageId = 0;
   203     length = 0;
   204     return NULL;
   205 }
   207 uint16 NameTable::getLanguageId(const char * bcp47Locale)
   208 {
   209     size_t localeLength = strlen(bcp47Locale);
   210     uint16 localeId = m_locale2Lang.getMsId(bcp47Locale);
   211     if (m_table && (be::swap<uint16>(m_table->format) == 1))
   212     {
   213         const uint8 * pLangEntries = reinterpret_cast<const uint8*>(m_table) +
   214             sizeof(TtfUtil::Sfnt::FontNames)
   215             + sizeof(TtfUtil::Sfnt::NameRecord) * ( be::swap<uint16>(m_table->count) - 1);
   216         uint16 numLangEntries = be::read<uint16>(pLangEntries);
   217         const TtfUtil::Sfnt::LangTagRecord * langTag =
   218             reinterpret_cast<const TtfUtil::Sfnt::LangTagRecord*>(pLangEntries);
   219         if (pLangEntries + numLangEntries * sizeof(TtfUtil::Sfnt::LangTagRecord) <= m_nameData)
   220         {
   221             for (uint16 i = 0; i < numLangEntries; i++)
   222             {
   223                 uint16 offset = be::swap<uint16>(langTag[i].offset);
   224                 uint16 length = be::swap<uint16>(langTag[i].length);
   225                 if ((offset + length <= m_nameDataLength) && (length == 2 * localeLength))
   226                 {
   227                     const uint8* pName = m_nameData + offset;
   228                     bool match = true;
   229                     for (size_t j = 0; j < localeLength; j++)
   230                     {
   231                         uint16 code = be::read<uint16>(pName);
   232                         if ((code > 0x7F) || (code != bcp47Locale[j]))
   233                         {
   234                             match = false;
   235                             break;
   236                         }
   237                     }
   238                     if (match)
   239                         return 0x8000 + i;
   240                 }
   241             }
   242         }
   243     }
   244     return localeId;
   245 }

mercurial