Home | History | Annotate | Download | only in src
      1 // Copyright (c) 2009 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 "os2.h"
      6 
      7 #include "head.h"
      8 
      9 // OS/2 - OS/2 and Windows Metrics
     10 // http://www.microsoft.com/opentype/otspec/os2.htm
     11 
     12 namespace ots {
     13 
     14 bool ots_os2_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
     15   Buffer table(data, length);
     16 
     17   OpenTypeOS2 *os2 = new OpenTypeOS2;
     18   file->os2 = os2;
     19 
     20   if (!table.ReadU16(&os2->version) ||
     21       !table.ReadS16(&os2->avg_char_width) ||
     22       !table.ReadU16(&os2->weight_class) ||
     23       !table.ReadU16(&os2->width_class) ||
     24       !table.ReadU16(&os2->type) ||
     25       !table.ReadS16(&os2->subscript_x_size) ||
     26       !table.ReadS16(&os2->subscript_y_size) ||
     27       !table.ReadS16(&os2->subscript_x_offset) ||
     28       !table.ReadS16(&os2->subscript_y_offset) ||
     29       !table.ReadS16(&os2->superscript_x_size) ||
     30       !table.ReadS16(&os2->superscript_y_size) ||
     31       !table.ReadS16(&os2->superscript_x_offset) ||
     32       !table.ReadS16(&os2->superscript_y_offset) ||
     33       !table.ReadS16(&os2->strikeout_size) ||
     34       !table.ReadS16(&os2->strikeout_position) ||
     35       !table.ReadS16(&os2->family_class)) {
     36     return OTS_FAILURE();
     37   }
     38 
     39   if (os2->version > 4) {
     40     return OTS_FAILURE();
     41   }
     42 
     43   // Some linux fonts (e.g., Kedage-t.ttf and LucidaSansDemiOblique.ttf) have
     44   // weird weight/width classes. Overwrite them with FW_NORMAL/1/9.
     45   if (os2->weight_class < 100 ||
     46       os2->weight_class > 900 ||
     47       os2->weight_class % 100) {
     48     OTS_WARNING("bad weight: %u", os2->weight_class);
     49     os2->weight_class = 400;  // FW_NORMAL
     50   }
     51   if (os2->width_class < 1) {
     52     OTS_WARNING("bad width: %u", os2->width_class);
     53     os2->width_class = 1;
     54   } else if (os2->width_class > 9) {
     55     OTS_WARNING("bad width: %u", os2->width_class);
     56     os2->width_class = 9;
     57   }
     58 
     59   // lowest 3 bits of fsType are exclusive.
     60   if (os2->type & 0x2) {
     61     // mask bits 2 & 3.
     62     os2->type &= 0xfff3u;
     63   } else if (os2->type & 0x4) {
     64     // mask bits 1 & 3.
     65     os2->type &= 0xfff4u;
     66   } else if (os2->type & 0x8) {
     67     // mask bits 1 & 2.
     68     os2->type &= 0xfff9u;
     69   }
     70 
     71   // mask reserved bits. use only 0..3, 8, 9 bits.
     72   os2->type &= 0x30f;
     73 
     74   if (os2->subscript_x_size < 0) {
     75     OTS_WARNING("bad subscript_x_size: %d", os2->subscript_x_size);
     76     os2->subscript_x_size = 0;
     77   }
     78   if (os2->subscript_y_size < 0) {
     79     OTS_WARNING("bad subscript_y_size: %d", os2->subscript_y_size);
     80     os2->subscript_y_size = 0;
     81   }
     82   if (os2->superscript_x_size < 0) {
     83     OTS_WARNING("bad superscript_x_size: %d", os2->superscript_x_size);
     84     os2->superscript_x_size = 0;
     85   }
     86   if (os2->superscript_y_size < 0) {
     87     OTS_WARNING("bad superscript_y_size: %d", os2->superscript_y_size);
     88     os2->superscript_y_size = 0;
     89   }
     90   if (os2->strikeout_size < 0) {
     91     OTS_WARNING("bad strikeout_size: %d", os2->strikeout_size);
     92     os2->strikeout_size = 0;
     93   }
     94 
     95   for (unsigned i = 0; i < 10; ++i) {
     96     if (!table.ReadU8(&os2->panose[i])) {
     97       return OTS_FAILURE();
     98     }
     99   }
    100 
    101   if (!table.ReadU32(&os2->unicode_range_1) ||
    102       !table.ReadU32(&os2->unicode_range_2) ||
    103       !table.ReadU32(&os2->unicode_range_3) ||
    104       !table.ReadU32(&os2->unicode_range_4) ||
    105       !table.ReadU32(&os2->vendor_id) ||
    106       !table.ReadU16(&os2->selection) ||
    107       !table.ReadU16(&os2->first_char_index) ||
    108       !table.ReadU16(&os2->last_char_index) ||
    109       !table.ReadS16(&os2->typo_ascender) ||
    110       !table.ReadS16(&os2->typo_descender) ||
    111       !table.ReadS16(&os2->typo_linegap) ||
    112       !table.ReadU16(&os2->win_ascent) ||
    113       !table.ReadU16(&os2->win_descent)) {
    114     return OTS_FAILURE();
    115   }
    116 
    117   // If bit 6 is set, then bits 0 and 5 must be clear.
    118   if (os2->selection & 0x40) {
    119     os2->selection &= 0xffdeu;
    120   }
    121 
    122   // the settings of bits 0 and 1 must be reflected in the macStyle bits
    123   // in the 'head' table.
    124   if (!file->head) {
    125     return OTS_FAILURE();
    126   }
    127   if ((os2->selection & 0x1) &&
    128       !(file->head->mac_style & 0x2)) {
    129     OTS_WARNING("adjusting Mac style (italic)");
    130     file->head->mac_style |= 0x2;
    131   }
    132   if ((os2->selection & 0x2) &&
    133       !(file->head->mac_style & 0x4)) {
    134     OTS_WARNING("adjusting Mac style (underscore)");
    135     file->head->mac_style |= 0x4;
    136   }
    137 
    138   // While bit 6 on implies that bits 0 and 1 of macStyle are clear,
    139   // the reverse is not true.
    140   if ((os2->selection & 0x40) &&
    141       (file->head->mac_style & 0x3)) {
    142     OTS_WARNING("adjusting Mac style (regular)");
    143     file->head->mac_style &= 0xfffcu;
    144   }
    145 
    146   if ((os2->version < 4) &&
    147       (os2->selection & 0x300)) {
    148     // bit 8 and 9 must be unset in OS/2 table versions less than 4.
    149     return OTS_FAILURE();
    150   }
    151 
    152   // mask reserved bits. use only 0..9 bits.
    153   os2->selection &= 0x3ff;
    154 
    155   if (os2->first_char_index > os2->last_char_index) {
    156     return OTS_FAILURE();
    157   }
    158   if (os2->typo_linegap < 0) {
    159     OTS_WARNING("bad linegap: %d", os2->typo_linegap);
    160     os2->typo_linegap = 0;
    161   }
    162 
    163   if (os2->version < 1) {
    164     // http://www.microsoft.com/typography/otspec/os2ver0.htm
    165     return true;
    166   }
    167 
    168   if (length < offsetof(OpenTypeOS2, code_page_range_2)) {
    169     OTS_WARNING("bad version number: %u", os2->version);
    170     // Some fonts (e.g., kredit1.ttf and quinquef.ttf) have weird version
    171     // numbers. Fix them.
    172     os2->version = 0;
    173     return true;
    174   }
    175 
    176   if (!table.ReadU32(&os2->code_page_range_1) ||
    177       !table.ReadU32(&os2->code_page_range_2)) {
    178     return OTS_FAILURE();
    179   }
    180 
    181   if (os2->version < 2) {
    182     // http://www.microsoft.com/typography/otspec/os2ver1.htm
    183     return true;
    184   }
    185 
    186   if (length < offsetof(OpenTypeOS2, max_context)) {
    187     OTS_WARNING("bad version number: %u", os2->version);
    188     // some Japanese fonts (e.g., mona.ttf) have weird version number.
    189     // fix them.
    190     os2->version = 1;
    191     return true;
    192   }
    193 
    194   if (!table.ReadS16(&os2->x_height) ||
    195       !table.ReadS16(&os2->cap_height) ||
    196       !table.ReadU16(&os2->default_char) ||
    197       !table.ReadU16(&os2->break_char) ||
    198       !table.ReadU16(&os2->max_context)) {
    199     return OTS_FAILURE();
    200   }
    201 
    202   if (os2->x_height < 0) {
    203     OTS_WARNING("bad x_height: %d", os2->x_height);
    204     os2->x_height = 0;
    205   }
    206   if (os2->cap_height < 0) {
    207     OTS_WARNING("bad cap_height: %d", os2->cap_height);
    208     os2->cap_height = 0;
    209   }
    210 
    211   return true;
    212 }
    213 
    214 bool ots_os2_should_serialise(OpenTypeFile *file) {
    215   return file->os2 != NULL;
    216 }
    217 
    218 bool ots_os2_serialise(OTSStream *out, OpenTypeFile *file) {
    219   const OpenTypeOS2 *os2 = file->os2;
    220 
    221   if (!out->WriteU16(os2->version) ||
    222       !out->WriteS16(os2->avg_char_width) ||
    223       !out->WriteU16(os2->weight_class) ||
    224       !out->WriteU16(os2->width_class) ||
    225       !out->WriteU16(os2->type) ||
    226       !out->WriteS16(os2->subscript_x_size) ||
    227       !out->WriteS16(os2->subscript_y_size) ||
    228       !out->WriteS16(os2->subscript_x_offset) ||
    229       !out->WriteS16(os2->subscript_y_offset) ||
    230       !out->WriteS16(os2->superscript_x_size) ||
    231       !out->WriteS16(os2->superscript_y_size) ||
    232       !out->WriteS16(os2->superscript_x_offset) ||
    233       !out->WriteS16(os2->superscript_y_offset) ||
    234       !out->WriteS16(os2->strikeout_size) ||
    235       !out->WriteS16(os2->strikeout_position) ||
    236       !out->WriteS16(os2->family_class)) {
    237     return OTS_FAILURE();
    238   }
    239 
    240   for (unsigned i = 0; i < 10; ++i) {
    241     if (!out->Write(&os2->panose[i], 1)) {
    242       return OTS_FAILURE();
    243     }
    244   }
    245 
    246   if (!out->WriteU32(os2->unicode_range_1) ||
    247       !out->WriteU32(os2->unicode_range_2) ||
    248       !out->WriteU32(os2->unicode_range_3) ||
    249       !out->WriteU32(os2->unicode_range_4) ||
    250       !out->WriteU32(os2->vendor_id) ||
    251       !out->WriteU16(os2->selection) ||
    252       !out->WriteU16(os2->first_char_index) ||
    253       !out->WriteU16(os2->last_char_index) ||
    254       !out->WriteS16(os2->typo_ascender) ||
    255       !out->WriteS16(os2->typo_descender) ||
    256       !out->WriteS16(os2->typo_linegap) ||
    257       !out->WriteU16(os2->win_ascent) ||
    258       !out->WriteU16(os2->win_descent)) {
    259     return OTS_FAILURE();
    260   }
    261 
    262   if (os2->version < 1) {
    263     return true;
    264   }
    265 
    266   if (!out->WriteU32(os2->code_page_range_1) ||
    267       !out->WriteU32(os2->code_page_range_2)) {
    268     return OTS_FAILURE();
    269   }
    270 
    271   if (os2->version < 2) {
    272     return true;
    273   }
    274 
    275   if (!out->WriteS16(os2->x_height) ||
    276       !out->WriteS16(os2->cap_height) ||
    277       !out->WriteU16(os2->default_char) ||
    278       !out->WriteU16(os2->break_char) ||
    279       !out->WriteU16(os2->max_context)) {
    280     return OTS_FAILURE();
    281   }
    282 
    283   return true;
    284 }
    285 
    286 void ots_os2_free(OpenTypeFile *file) {
    287   delete file->os2;
    288 }
    289 
    290 }  // namespace ots
    291