LCOV - code coverage report
Current view: directory - gfx/ots/src - name.cc (source / functions) Found Hit Coverage
Test: app.info Lines: 175 0 0.0 %
Date: 2012-06-02 Functions: 8 0 0.0 %

       1                 : // Copyright (c) 2011 The Chromium Authors. All rights reserved.
       2                 : // Use of this source code is governed by a BSD-style license that can be
       3                 : // found in the LICENSE file.
       4                 : 
       5                 : #include "name.h"
       6                 : 
       7                 : #include <algorithm>
       8                 : #include <cstring>
       9                 : 
      10                 : #include "cff.h"
      11                 : 
      12                 : // name - Naming Table
      13                 : // http://www.microsoft.com/opentype/otspec/name.htm
      14                 : 
      15                 : namespace {
      16                 : 
      17               0 : bool ValidInPsName(char c) {
      18               0 :   return (c > 0x20 && c < 0x7f && !std::strchr("[](){}<>/%", c));
      19                 : }
      20                 : 
      21               0 : bool CheckPsNameAscii(const std::string& name) {
      22               0 :   for (unsigned i = 0; i < name.size(); ++i) {
      23               0 :     if (!ValidInPsName(name[i])) {
      24               0 :       return false;
      25                 :     }
      26                 :   }
      27               0 :   return true;
      28                 : }
      29                 : 
      30               0 : bool CheckPsNameUtf16Be(const std::string& name) {
      31               0 :   if ((name.size() & 1) != 0)
      32               0 :     return false;
      33                 : 
      34               0 :   for (unsigned i = 0; i < name.size(); i += 2) {
      35               0 :     if (name[i] != 0) {
      36               0 :       return false;
      37                 :     }
      38               0 :     if (!ValidInPsName(name[i+1])) {
      39               0 :       return false;
      40                 :     }
      41                 :   }
      42               0 :   return true;
      43                 : }
      44                 : 
      45               0 : void AssignToUtf16BeFromAscii(std::string* target,
      46                 :                               const std::string& source) {
      47               0 :   target->resize(source.size() * 2);
      48               0 :   for (unsigned i = 0, j = 0; i < source.size(); i++) {
      49               0 :     (*target)[j++] = '\0';
      50               0 :     (*target)[j++] = source[i];
      51                 :   }
      52               0 : }
      53                 : 
      54                 : }  // namespace
      55                 : 
      56                 : 
      57                 : namespace ots {
      58                 : 
      59               0 : bool ots_name_parse(OpenTypeFile* file, const uint8_t* data, size_t length) {
      60               0 :   Buffer table(data, length);
      61                 : 
      62               0 :   OpenTypeNAME* name = new OpenTypeNAME;
      63               0 :   file->name = name;
      64                 : 
      65               0 :   uint16_t format = 0;
      66               0 :   if (!table.ReadU16(&format) || format > 1) {
      67               0 :     return OTS_FAILURE();
      68                 :   }
      69                 : 
      70               0 :   uint16_t count = 0;
      71               0 :   if (!table.ReadU16(&count)) {
      72               0 :     return OTS_FAILURE();
      73                 :   }
      74                 : 
      75               0 :   uint16_t string_offset = 0;
      76               0 :   if (!table.ReadU16(&string_offset) || string_offset > length) {
      77               0 :     return OTS_FAILURE();
      78                 :   }
      79                 :   const char* string_base = reinterpret_cast<const char*>(data) +
      80               0 :       string_offset;
      81                 : 
      82               0 :   NameRecord prev_record;
      83               0 :   bool sort_required = false;
      84                 : 
      85                 :   // Read all the names, discarding any with invalid IDs,
      86                 :   // and any where the offset/length would be outside the table.
      87                 :   // A stricter alternative would be to reject the font if there
      88                 :   // are invalid name records, but it's not clear that is necessary.
      89               0 :   for (unsigned i = 0; i < count; ++i) {
      90               0 :     NameRecord rec;
      91                 :     uint16_t name_length, name_offset;
      92               0 :     if (!table.ReadU16(&rec.platform_id) ||
      93               0 :         !table.ReadU16(&rec.encoding_id) ||
      94               0 :         !table.ReadU16(&rec.language_id) ||
      95               0 :         !table.ReadU16(&rec.name_id) ||
      96               0 :         !table.ReadU16(&name_length) ||
      97               0 :         !table.ReadU16(&name_offset)) {
      98               0 :       return OTS_FAILURE();
      99                 :     }
     100                 :     // check platform & encoding, discard names with unknown values
     101               0 :     switch (rec.platform_id) {
     102                 :       case 0:  // Unicode
     103               0 :         if (rec.encoding_id > 6) {
     104               0 :           continue;
     105                 :         }
     106               0 :         break;
     107                 :       case 1:  // Macintosh
     108               0 :         if (rec.encoding_id > 32) {
     109               0 :           continue;
     110                 :         }
     111               0 :         break;
     112                 :       case 2:  // ISO
     113               0 :         if (rec.encoding_id > 2) {
     114               0 :           continue;
     115                 :         }
     116               0 :         break;
     117                 :       case 3:  // Windows: IDs 7 to 9 are "reserved"
     118               0 :         if (rec.encoding_id > 6 && rec.encoding_id != 10) {
     119               0 :           continue;
     120                 :         }
     121               0 :         break;
     122                 :       case 4:  // Custom (OTF Windows NT compatibility)
     123               0 :         if (rec.encoding_id > 255) {
     124               0 :           continue;
     125                 :         }
     126               0 :         break;
     127                 :       default:  // unknown platform
     128               0 :         continue;
     129                 :     }
     130                 : 
     131                 :     const unsigned name_end = static_cast<unsigned>(string_offset) +
     132               0 :         name_offset + name_length;
     133               0 :     if (name_end > length) {
     134               0 :       continue;
     135                 :     }
     136               0 :     rec.text.resize(name_length);
     137               0 :     rec.text.assign(string_base + name_offset, name_length);
     138                 : 
     139               0 :     if (rec.name_id == 6) {
     140                 :       // PostScript name: check that it is valid, if not then discard it
     141               0 :       if (rec.platform_id == 1) {
     142               0 :         if (file->cff && !file->cff->name.empty()) {
     143               0 :           rec.text = file->cff->name;
     144               0 :         } else if (!CheckPsNameAscii(rec.text)) {
     145               0 :           continue;
     146                 :         }
     147               0 :       } else if (rec.platform_id == 0 || rec.platform_id == 3) {
     148               0 :         if (file->cff && !file->cff->name.empty()) {
     149               0 :           AssignToUtf16BeFromAscii(&rec.text, file->cff->name);
     150               0 :         } else if (!CheckPsNameUtf16Be(rec.text)) {
     151               0 :           continue;
     152                 :         }
     153                 :       }
     154                 :     }
     155                 : 
     156               0 :     if ((i > 0) && !(prev_record < rec)) {
     157                 :       OTS_WARNING("name records are not sorted.");
     158               0 :       sort_required = true;
     159                 :     }
     160                 : 
     161               0 :     name->names.push_back(rec);
     162               0 :     prev_record = rec;
     163                 :   }
     164                 : 
     165               0 :   if (format == 1) {
     166                 :     // extended name table format with language tags
     167                 :     uint16_t lang_tag_count;
     168               0 :     if (!table.ReadU16(&lang_tag_count)) {
     169               0 :       return OTS_FAILURE();
     170                 :     }
     171               0 :     for (unsigned i = 0; i < lang_tag_count; ++i) {
     172               0 :       uint16_t tag_length = 0;
     173               0 :       uint16_t tag_offset = 0;
     174               0 :       if (!table.ReadU16(&tag_length) || !table.ReadU16(&tag_offset)) {
     175               0 :         return OTS_FAILURE();
     176                 :       }
     177                 :       const unsigned tag_end = static_cast<unsigned>(string_offset) +
     178               0 :           tag_offset + tag_length;
     179               0 :       if (tag_end > length) {
     180               0 :         return OTS_FAILURE();
     181                 :       }
     182               0 :       std::string tag(string_base + tag_offset, tag_length);
     183               0 :       name->lang_tags.push_back(tag);
     184                 :     }
     185                 :   }
     186                 : 
     187               0 :   if (table.offset() > string_offset) {
     188                 :     // the string storage apparently overlapped the name/tag records;
     189                 :     // consider this font to be badly broken
     190               0 :     return OTS_FAILURE();
     191                 :   }
     192                 : 
     193                 :   // check existence of required name strings (synthesize if necessary)
     194                 :   //  [0 - copyright - skip]
     195                 :   //   1 - family
     196                 :   //   2 - subfamily
     197                 :   //  [3 - unique ID - skip]
     198                 :   //   4 - full name
     199                 :   //   5 - version
     200                 :   //   6 - postscript name
     201                 :   static const unsigned kStdNameCount = 7;
     202                 :   static const char* kStdNames[kStdNameCount] = {
     203                 :     NULL,
     204                 :     "OTS derived font",
     205                 :     "Unspecified",
     206                 :     NULL,
     207                 :     "OTS derived font",
     208                 :     "1.000",
     209                 :     "OTS-derived-font"
     210                 :   };
     211                 :   // The spec says that "In CFF OpenType fonts, these two name strings, when
     212                 :   // translated to ASCII, must also be identical to the font name as stored in
     213                 :   // the CFF's Name INDEX." And actually, Mac OS X's font parser requires that.
     214               0 :   if (file->cff && !file->cff->name.empty()) {
     215               0 :     kStdNames[6] = file->cff->name.c_str();
     216                 :   }
     217                 : 
     218                 :   // scan the names to check whether the required "standard" ones are present;
     219                 :   // if not, we'll add our fixed versions here
     220               0 :   bool mac_name[kStdNameCount] = { 0 };
     221               0 :   bool win_name[kStdNameCount] = { 0 };
     222               0 :   for (std::vector<NameRecord>::iterator name_iter = name->names.begin();
     223               0 :        name_iter != name->names.end(); name_iter++) {
     224               0 :     const uint16_t id = name_iter->name_id;
     225               0 :     if (id >= kStdNameCount || kStdNames[id] == NULL) {
     226               0 :       continue;
     227                 :     }
     228               0 :     if (name_iter->platform_id == 1) {
     229               0 :       mac_name[id] = true;
     230               0 :       continue;
     231                 :     }
     232               0 :     if (name_iter->platform_id == 3) {
     233               0 :       win_name[id] = true;
     234               0 :       continue;
     235                 :     }
     236                 :   }
     237                 : 
     238               0 :   for (unsigned i = 0; i < kStdNameCount; ++i) {
     239               0 :     if (kStdNames[i] == NULL) {
     240               0 :       continue;
     241                 :     }
     242               0 :     if (!mac_name[i]) {
     243                 :       NameRecord rec(1 /* platform_id */, 0 /* encoding_id */,
     244               0 :                      0 /* language_id */ , i /* name_id */);
     245               0 :       rec.text.assign(kStdNames[i]);
     246               0 :       name->names.push_back(rec);
     247               0 :       sort_required = true;
     248                 :     }
     249               0 :     if (!win_name[i]) {
     250                 :       NameRecord rec(3 /* platform_id */, 1 /* encoding_id */,
     251               0 :                      1033 /* language_id */ , i /* name_id */);
     252               0 :       AssignToUtf16BeFromAscii(&rec.text, std::string(kStdNames[i]));
     253               0 :       name->names.push_back(rec);
     254               0 :       sort_required = true;
     255                 :     }
     256                 :   }
     257                 : 
     258               0 :   if (sort_required) {
     259               0 :     std::sort(name->names.begin(), name->names.end());
     260                 :   }
     261                 : 
     262               0 :   return true;
     263                 : }
     264                 : 
     265               0 : bool ots_name_should_serialise(OpenTypeFile* file) {
     266               0 :   return file->name != NULL;
     267                 : }
     268                 : 
     269               0 : bool ots_name_serialise(OTSStream* out, OpenTypeFile* file) {
     270               0 :   const OpenTypeNAME* name = file->name;
     271                 : 
     272               0 :   uint16_t name_count = name->names.size();
     273               0 :   uint16_t lang_tag_count = name->lang_tags.size();
     274               0 :   uint16_t format = 0;
     275               0 :   size_t string_offset = 6 + name_count * 12;
     276                 : 
     277               0 :   if (name->lang_tags.size() > 0) {
     278                 :     // lang tags require a format-1 name table
     279               0 :     format = 1;
     280               0 :     string_offset += 2 + lang_tag_count * 4;
     281                 :   }
     282               0 :   if (string_offset > 0xffff) {
     283               0 :     return OTS_FAILURE();
     284                 :   }
     285               0 :   if (!out->WriteU16(format) ||
     286               0 :       !out->WriteU16(name_count) ||
     287               0 :       !out->WriteU16(string_offset)) {
     288               0 :     return OTS_FAILURE();
     289                 :   }
     290                 : 
     291               0 :   std::string string_data;
     292               0 :   for (std::vector<NameRecord>::const_iterator name_iter = name->names.begin();
     293               0 :        name_iter != name->names.end(); name_iter++) {
     294               0 :     const NameRecord& rec = *name_iter;
     295               0 :     if (!out->WriteU16(rec.platform_id) ||
     296               0 :         !out->WriteU16(rec.encoding_id) ||
     297               0 :         !out->WriteU16(rec.language_id) ||
     298               0 :         !out->WriteU16(rec.name_id) ||
     299               0 :         !out->WriteU16(rec.text.size()) ||
     300               0 :         !out->WriteU16(string_data.size()) ) {
     301               0 :       return OTS_FAILURE();
     302                 :     }
     303               0 :     string_data.append(rec.text);
     304                 :   }
     305                 : 
     306               0 :   if (format == 1) {
     307               0 :     if (!out->WriteU16(lang_tag_count)) {
     308               0 :       return OTS_FAILURE();
     309                 :     }
     310               0 :     for (std::vector<std::string>::const_iterator tag_iter =
     311               0 :              name->lang_tags.begin();
     312               0 :          tag_iter != name->lang_tags.end(); tag_iter++) {
     313               0 :       if (!out->WriteU16(tag_iter->size()) ||
     314               0 :           !out->WriteU16(string_data.size())) {
     315               0 :         return OTS_FAILURE();
     316                 :       }
     317               0 :       string_data.append(*tag_iter);
     318                 :     }
     319                 :   }
     320                 : 
     321               0 :   if (!out->Write(string_data.data(), string_data.size())) {
     322               0 :     return OTS_FAILURE();
     323                 :   }
     324                 : 
     325               0 :   return true;
     326                 : }
     327                 : 
     328               0 : void ots_name_free(OpenTypeFile* file) {
     329               0 :   delete file->name;
     330               0 : }
     331                 : 
     332                 : }  // namespace

Generated by: LCOV version 1.7