diff --git a/ots-common.gypi b/ots-common.gypi index f023de36..0432b4ac 100644 --- a/ots-common.gypi +++ b/ots-common.gypi @@ -45,6 +45,8 @@ 'src/ltsh.h', 'src/maxp.cc', 'src/maxp.h', + 'src/metrics.cc', + 'src/metrics.h', 'src/name.cc', 'src/os2.cc', 'src/os2.h', @@ -56,6 +58,10 @@ 'src/prep.h', 'src/vdmx.cc', 'src/vdmx.h', + 'src/vhea.cc', + 'src/vhea.h', + 'src/vmtx.cc', + 'src/vmtx.h', 'src/vorg.cc', 'src/vorg.h', ], diff --git a/src/hhea.cc b/src/hhea.cc index f9f81b54..0342ba5b 100644 --- a/src/hhea.cc +++ b/src/hhea.cc @@ -17,69 +17,14 @@ bool ots_hhea_parse(OpenTypeFile *file, const uint8_t *data, size_t length) { OpenTypeHHEA *hhea = new OpenTypeHHEA; file->hhea = hhea; - uint32_t version = 0; - if (!table.ReadU32(&version)) { + if (!table.ReadU32(&hhea->header.version)) { return OTS_FAILURE(); } - if (version >> 16 != 1) { + if (hhea->header.version >> 16 != 1) { return OTS_FAILURE(); } - if (!table.ReadS16(&hhea->ascent) || - !table.ReadS16(&hhea->descent) || - !table.ReadS16(&hhea->linegap) || - !table.ReadU16(&hhea->adv_width_max) || - !table.ReadS16(&hhea->min_lsb) || - !table.ReadS16(&hhea->min_rsb) || - !table.ReadS16(&hhea->x_max_extent) || - !table.ReadS16(&hhea->caret_slope_rise) || - !table.ReadS16(&hhea->caret_slope_run) || - !table.ReadS16(&hhea->caret_offset)) { - return OTS_FAILURE(); - } - - if (hhea->ascent < 0) { - OTS_WARNING("bad ascent: %d", hhea->ascent); - hhea->ascent = 0; - } - if (hhea->linegap < 0) { - OTS_WARNING("bad linegap: %d", hhea->linegap); - hhea->linegap = 0; - } - - if (!file->head) { - return OTS_FAILURE(); - } - - // if the font is non-slanted, caret_offset should be zero. - if (!(file->head->mac_style & 2) && - (hhea->caret_offset != 0)) { - OTS_WARNING("bad caret offset: %d", hhea->caret_offset); - hhea->caret_offset = 0; - } - - // skip the reserved bytes - if (!table.Skip(8)) { - return OTS_FAILURE(); - } - - int16_t data_format; - if (!table.ReadS16(&data_format)) { - return OTS_FAILURE(); - } - if (data_format) { - return OTS_FAILURE(); - } - - if (!table.ReadU16(&hhea->num_hmetrics)) { - return OTS_FAILURE(); - } - - if (!file->maxp) { - return OTS_FAILURE(); - } - - if (hhea->num_hmetrics > file->maxp->num_glyphs) { + if (!ParseMetricsHeader(file, &table, &hhea->header)) { return OTS_FAILURE(); } @@ -91,25 +36,9 @@ bool ots_hhea_should_serialise(OpenTypeFile *file) { } bool ots_hhea_serialise(OTSStream *out, OpenTypeFile *file) { - const OpenTypeHHEA *hhea = file->hhea; - - if (!out->WriteU32(0x00010000) || - !out->WriteS16(hhea->ascent) || - !out->WriteS16(hhea->descent) || - !out->WriteS16(hhea->linegap) || - !out->WriteU16(hhea->adv_width_max) || - !out->WriteS16(hhea->min_lsb) || - !out->WriteS16(hhea->min_rsb) || - !out->WriteS16(hhea->x_max_extent) || - !out->WriteS16(hhea->caret_slope_rise) || - !out->WriteS16(hhea->caret_slope_run) || - !out->WriteS16(hhea->caret_offset) || - !out->WriteR64(0) || // reserved - !out->WriteS16(0) || // metric data format - !out->WriteU16(hhea->num_hmetrics)) { + if (!SerialiseMetricsHeader(out, &file->hhea->header)) { return OTS_FAILURE(); } - return true; } diff --git a/src/hhea.h b/src/hhea.h index 99aafde3..bdea9aa0 100644 --- a/src/hhea.h +++ b/src/hhea.h @@ -5,22 +5,13 @@ #ifndef OTS_HHEA_H_ #define OTS_HHEA_H_ +#include "metrics.h" #include "ots.h" namespace ots { struct OpenTypeHHEA { - int16_t ascent; - int16_t descent; - int16_t linegap; - uint16_t adv_width_max; - int16_t min_lsb; - int16_t min_rsb; - int16_t x_max_extent; - int16_t caret_slope_rise; - int16_t caret_slope_run; - int16_t caret_offset; - uint16_t num_hmetrics; + OpenTypeMetricsHeader header; }; } // namespace ots diff --git a/src/hmtx.cc b/src/hmtx.cc index 3dcaccdd..ea7491d2 100644 --- a/src/hmtx.cc +++ b/src/hmtx.cc @@ -21,58 +21,10 @@ bool ots_hmtx_parse(OpenTypeFile *file, const uint8_t *data, size_t length) { return OTS_FAILURE(); } - // |num_hmetrics| is a uint16_t, so it's bounded < 65536. This limits that - // amount of memory that we'll allocate for this to a sane amount. - const unsigned num_hmetrics = file->hhea->num_hmetrics; - - if (num_hmetrics > file->maxp->num_glyphs) { - return OTS_FAILURE(); - } - if (!num_hmetrics) { + if (!ParseMetricsTable(&table, file->maxp->num_glyphs, + &file->hhea->header, &hmtx->metrics)) { return OTS_FAILURE(); } - const unsigned num_lsbs = file->maxp->num_glyphs - num_hmetrics; - - hmtx->metrics.reserve(num_hmetrics); - for (unsigned i = 0; i < num_hmetrics; ++i) { - uint16_t adv = 0; - int16_t lsb = 0; - if (!table.ReadU16(&adv) || !table.ReadS16(&lsb)) { - return OTS_FAILURE(); - } - - // Since so many fonts don't have proper value on |adv| and |lsb|, - // we should not call ots_failure() here. For example, about 20% of fonts - // in http://www.princexml.com/fonts/ (200+ fonts) fails these tests. - if (adv > file->hhea->adv_width_max) { - OTS_WARNING("bad adv: %u > %u", adv, file->hhea->adv_width_max); - adv = file->hhea->adv_width_max; - } - if (lsb < file->hhea->min_lsb) { - OTS_WARNING("bad lsb: %d < %d", lsb, file->hhea->min_lsb); - lsb = file->hhea->min_lsb; - } - - hmtx->metrics.push_back(std::make_pair(adv, lsb)); - } - - hmtx->lsbs.reserve(num_lsbs); - for (unsigned i = 0; i < num_lsbs; ++i) { - int16_t lsb; - if (!table.ReadS16(&lsb)) { - // Some Japanese fonts (e.g., mona.ttf) fail this test. - return OTS_FAILURE(); - } - - if (lsb < file->hhea->min_lsb) { - // The same as above. Three fonts in http://www.fontsquirrel.com/fontface - // (e.g., Notice2Std.otf) have weird lsb values. - OTS_WARNING("bad lsb: %d < %d", lsb, file->hhea->min_lsb); - lsb = file->hhea->min_lsb; - } - - hmtx->lsbs.push_back(lsb); - } return true; } @@ -82,21 +34,9 @@ bool ots_hmtx_should_serialise(OpenTypeFile *file) { } bool ots_hmtx_serialise(OTSStream *out, OpenTypeFile *file) { - const OpenTypeHMTX *hmtx = file->hmtx; - - for (unsigned i = 0; i < hmtx->metrics.size(); ++i) { - if (!out->WriteU16(hmtx->metrics[i].first) || - !out->WriteS16(hmtx->metrics[i].second)) { - return OTS_FAILURE(); - } - } - - for (unsigned i = 0; i < hmtx->lsbs.size(); ++i) { - if (!out->WriteS16(hmtx->lsbs[i])) { - return OTS_FAILURE(); - } + if (!SerialiseMetricsTable(out, &file->hmtx->metrics)) { + return OTS_FAILURE(); } - return true; } diff --git a/src/hmtx.h b/src/hmtx.h index 79a9cb6d..435949c5 100644 --- a/src/hmtx.h +++ b/src/hmtx.h @@ -5,16 +5,13 @@ #ifndef OTS_HMTX_H_ #define OTS_HMTX_H_ -#include // std::pair -#include - +#include "metrics.h" #include "ots.h" namespace ots { struct OpenTypeHMTX { - std::vector > metrics; - std::vector lsbs; + OpenTypeMetricsTable metrics; }; } // namespace ots diff --git a/src/metrics.cc b/src/metrics.cc new file mode 100644 index 00000000..2e9190f1 --- /dev/null +++ b/src/metrics.cc @@ -0,0 +1,181 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "metrics.h" + +#include "head.h" +#include "maxp.h" + +// OpenType horizontal and vertical common header format +// http://www.microsoft.com/opentype/otspec/hhea.htm +// http://www.microsoft.com/opentype/otspec/vhea.htm + +namespace ots { + +bool ParseMetricsHeader(OpenTypeFile *file, Buffer *table, + OpenTypeMetricsHeader *header) { + if (!table->ReadS16(&header->ascent) || + !table->ReadS16(&header->descent) || + !table->ReadS16(&header->linegap) || + !table->ReadU16(&header->adv_width_max) || + !table->ReadS16(&header->min_sb1) || + !table->ReadS16(&header->min_sb2) || + !table->ReadS16(&header->max_extent) || + !table->ReadS16(&header->caret_slope_rise) || + !table->ReadS16(&header->caret_slope_run) || + !table->ReadS16(&header->caret_offset)) { + return OTS_FAILURE(); + } + + if (header->ascent < 0) { + OTS_WARNING("bad ascent: %d", header->ascent); + header->ascent = 0; + } + if (header->linegap < 0) { + OTS_WARNING("bad linegap: %d", header->linegap); + header->linegap = 0; + } + + if (!file->head) { + return OTS_FAILURE(); + } + + // if the font is non-slanted, caret_offset should be zero. + if (!(file->head->mac_style & 2) && + (header->caret_offset != 0)) { + OTS_WARNING("bad caret offset: %d", header->caret_offset); + header->caret_offset = 0; + } + + // skip the reserved bytes + if (!table->Skip(8)) { + return OTS_FAILURE(); + } + + int16_t data_format; + if (!table->ReadS16(&data_format)) { + return OTS_FAILURE(); + } + if (data_format) { + return OTS_FAILURE(); + } + + if (!table->ReadU16(&header->num_metrics)) { + return OTS_FAILURE(); + } + + if (!file->maxp) { + return OTS_FAILURE(); + } + + if (header->num_metrics > file->maxp->num_glyphs) { + return OTS_FAILURE(); + } + + return true; +} + +bool SerialiseMetricsHeader(OTSStream *out, + const OpenTypeMetricsHeader *header) { + if (!out->WriteU32(header->version) || + !out->WriteS16(header->ascent) || + !out->WriteS16(header->descent) || + !out->WriteS16(header->linegap) || + !out->WriteU16(header->adv_width_max) || + !out->WriteS16(header->min_sb1) || + !out->WriteS16(header->min_sb2) || + !out->WriteS16(header->max_extent) || + !out->WriteS16(header->caret_slope_rise) || + !out->WriteS16(header->caret_slope_run) || + !out->WriteS16(header->caret_offset) || + !out->WriteR64(0) || // reserved + !out->WriteS16(0) || // metric data format + !out->WriteU16(header->num_metrics)) { + return OTS_FAILURE(); + } + + return true; +} + +bool ParseMetricsTable(Buffer *table, + const uint16_t num_glyphs, + const OpenTypeMetricsHeader *header, + OpenTypeMetricsTable *metrics) { + // |num_metrics| is a uint16_t, so it's bounded < 65536. This limits that + // amount of memory that we'll allocate for this to a sane amount. + const unsigned num_metrics = header->num_metrics; + + if (num_metrics > num_glyphs) { + return OTS_FAILURE(); + } + if (!num_metrics) { + return OTS_FAILURE(); + } + const unsigned num_sbs = num_glyphs - num_metrics; + + metrics->entries.reserve(num_metrics); + for (unsigned i = 0; i < num_metrics; ++i) { + uint16_t adv = 0; + int16_t sb = 0; + if (!table->ReadU16(&adv) || !table->ReadS16(&sb)) { + return OTS_FAILURE(); + } + + // Since so many fonts don't have proper value on |adv| and |sb|, + // we should not call ots_failure() here. For example, about 20% of fonts + // in http://www.princexml.com/fonts/ (200+ fonts) fails these tests. + if (adv > header->adv_width_max) { + OTS_WARNING("bad adv: %u > %u", adv, header->adv_width_max); + adv = header->adv_width_max; + } + + if (sb < header->min_sb1) { + OTS_WARNING("bad sb: %d < %d", sb, header->min_sb1); + sb = header->min_sb1; + } + + metrics->entries.push_back(std::make_pair(adv, sb)); + } + + metrics->sbs.reserve(num_sbs); + for (unsigned i = 0; i < num_sbs; ++i) { + int16_t sb; + if (!table->ReadS16(&sb)) { + // Some Japanese fonts (e.g., mona.ttf) fail this test. + return OTS_FAILURE(); + } + + if (sb < header->min_sb1) { + // The same as above. Three fonts in http://www.fontsquirrel.com/fontface + // (e.g., Notice2Std.otf) have weird lsb values. + OTS_WARNING("bad lsb: %d < %d", sb, header->min_sb1); + sb = header->min_sb1; + } + + metrics->sbs.push_back(sb); + } + + return true; +} + +bool SerialiseMetricsTable(OTSStream *out, + const OpenTypeMetricsTable *metrics) { + for (unsigned i = 0; i < metrics->entries.size(); ++i) { + if (!out->WriteU16(metrics->entries[i].first) || + !out->WriteS16(metrics->entries[i].second)) { + return OTS_FAILURE(); + } + } + + for (unsigned i = 0; i < metrics->sbs.size(); ++i) { + if (!out->WriteS16(metrics->sbs[i])) { + return OTS_FAILURE(); + } + } + + return true; +} + +} // namespace ots + diff --git a/src/metrics.h b/src/metrics.h new file mode 100644 index 00000000..46559e17 --- /dev/null +++ b/src/metrics.h @@ -0,0 +1,50 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef OTS_METRICS_H_ +#define OTS_METRICS_H_ + +#include // std::pair +#include + +#include "ots.h" + +namespace ots { + +struct OpenTypeMetricsHeader { + uint32_t version; + int16_t ascent; + int16_t descent; + int16_t linegap; + uint16_t adv_width_max; + int16_t min_sb1; + int16_t min_sb2; + int16_t max_extent; + int16_t caret_slope_rise; + int16_t caret_slope_run; + int16_t caret_offset; + uint16_t num_metrics; +}; + +struct OpenTypeMetricsTable { + std::vector > entries; + std::vector sbs; +}; + +bool ParseMetricsHeader(OpenTypeFile *file, Buffer *table, + OpenTypeMetricsHeader *header); +bool SerialiseMetricsHeader(OTSStream *out, + const OpenTypeMetricsHeader *header); + +bool ParseMetricsTable(Buffer *table, + const uint16_t num_glyphs, + const OpenTypeMetricsHeader *header, + OpenTypeMetricsTable *metrics); +bool SerialiseMetricsTable(OTSStream *out, + const OpenTypeMetricsTable *metrics); + +} // namespace ots + +#endif // OTS_METRICS_H_ + diff --git a/src/ots.cc b/src/ots.cc index 75d9a35c..ff0ee76e 100644 --- a/src/ots.cc +++ b/src/ots.cc @@ -16,17 +16,6 @@ // The OpenType Font File // http://www.microsoft.com/typography/otspec/cmap.htm -#define F(name, capname) \ - namespace ots { \ - bool ots_##name##_parse(OpenTypeFile *f, const uint8_t *d, size_t l); \ - bool ots_##name##_should_serialise(OpenTypeFile *f); \ - bool ots_##name##_serialise(OTSStream *s, OpenTypeFile *f); \ - void ots_##name##_free(OpenTypeFile *f); \ - } - // TODO(yusukes): change these function names to follow Chromium coding rule. -FOR_EACH_TABLE_TYPE -#undef F - namespace { bool g_debug_output = true; @@ -150,6 +139,10 @@ const struct { ots::ots_gpos_should_serialise, ots::ots_gpos_free, false }, { Tag("GSUB"), ots::ots_gsub_parse, ots::ots_gsub_serialise, ots::ots_gsub_should_serialise, ots::ots_gsub_free, false }, + { Tag("vhea"), ots::ots_vhea_parse, ots::ots_vhea_serialise, + ots::ots_vhea_should_serialise, ots::ots_vhea_free, false }, + { Tag("vmtx"), ots::ots_vmtx_parse, ots::ots_vmtx_serialise, + ots::ots_vmtx_should_serialise, ots::ots_vmtx_free, false }, // TODO(bashi): Support mort, base, and jstf tables. { 0, NULL, NULL, NULL, NULL, false }, }; diff --git a/src/ots.h b/src/ots.h index 8ba30b31..5acb81fb 100644 --- a/src/ots.h +++ b/src/ots.h @@ -179,7 +179,9 @@ class Buffer { F(post, POST) \ F(prep, PREP) \ F(vdmx, VDMX) \ - F(vorg, VORG) + F(vorg, VORG) \ + F(vhea, VHEA) \ + F(vmtx, VMTX) #define F(name, capname) struct OpenType##capname; FOR_EACH_TABLE_TYPE @@ -203,6 +205,15 @@ FOR_EACH_TABLE_TYPE #undef F }; +#define F(name, capname) \ +bool ots_##name##_parse(OpenTypeFile *f, const uint8_t *d, size_t l); \ +bool ots_##name##_should_serialise(OpenTypeFile *f); \ +bool ots_##name##_serialise(OTSStream *s, OpenTypeFile *f); \ +void ots_##name##_free(OpenTypeFile *f); +// TODO(yusukes): change these function names to follow Chromium coding rule. +FOR_EACH_TABLE_TYPE +#undef F + } // namespace ots #endif // OTS_H_ diff --git a/src/vhea.cc b/src/vhea.cc new file mode 100644 index 00000000..b37b73a7 --- /dev/null +++ b/src/vhea.cc @@ -0,0 +1,56 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "vhea.h" + +#include "gsub.h" +#include "head.h" +#include "maxp.h" + +// vhea - Vertical Header Table +// http://www.microsoft.com/opentype/otspec/vhea.htm + +namespace ots { + +bool ots_vhea_parse(OpenTypeFile *file, const uint8_t *data, size_t length) { + Buffer table(data, length); + OpenTypeVHEA *vhea = new OpenTypeVHEA; + file->vhea = vhea; + + if (!table.ReadU32(&vhea->header.version)) { + return OTS_FAILURE(); + } + if (vhea->header.version != 0x00010000 && + vhea->header.version != 0x00011000) { + return OTS_FAILURE(); + } + + if (!ParseMetricsHeader(file, &table, &vhea->header)) { + return OTS_FAILURE(); + } + + return true; +} + +bool ots_vhea_should_serialise(OpenTypeFile *file) { + // vhea should'nt serialise when vmtx doesn't exist. + // Firefox developer pointed out that vhea/vmtx should serialise iff GSUB is + // preserved. See http://crbug.com/77386 + return file->vhea != NULL && file->vmtx != NULL && + ots_gsub_should_serialise(file); +} + +bool ots_vhea_serialise(OTSStream *out, OpenTypeFile *file) { + if (!SerialiseMetricsHeader(out, &file->vhea->header)) { + return OTS_FAILURE(); + } + return true; +} + +void ots_vhea_free(OpenTypeFile *file) { + delete file->vhea; +} + +} // namespace ots + diff --git a/src/vhea.h b/src/vhea.h new file mode 100644 index 00000000..f8efde73 --- /dev/null +++ b/src/vhea.h @@ -0,0 +1,20 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef OTS_VHEA_H_ +#define OTS_VHEA_H_ + +#include "metrics.h" +#include "ots.h" + +namespace ots { + +struct OpenTypeVHEA { + OpenTypeMetricsHeader header; +}; + +} // namespace ots + +#endif // OTS_VHEA_H_ + diff --git a/src/vmtx.cc b/src/vmtx.cc new file mode 100644 index 00000000..04761aba --- /dev/null +++ b/src/vmtx.cc @@ -0,0 +1,52 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "vmtx.h" + +#include "gsub.h" +#include "maxp.h" +#include "vhea.h" + +// vmtx - Vertical Metrics Table +// http://www.microsoft.com/opentype/otspec/vmtx.htm + +namespace ots { + +bool ots_vmtx_parse(OpenTypeFile *file, const uint8_t *data, size_t length) { + Buffer table(data, length); + OpenTypeVMTX *vmtx = new OpenTypeVMTX; + file->vmtx = vmtx; + + if (!file->vhea || !file->maxp) { + return OTS_FAILURE(); + } + + if (!ParseMetricsTable(&table, file->maxp->num_glyphs, + &file->vhea->header, &vmtx->metrics)) { + return OTS_FAILURE(); + } + + return true; +} + +bool ots_vmtx_should_serialise(OpenTypeFile *file) { + // vmtx should serialise when vhea and GSUB are preserved. + // See the comment in ots_vhea_should_serialise(). + return file->vmtx != NULL && file->vhea != NULL && + ots_gsub_should_serialise(file); +} + +bool ots_vmtx_serialise(OTSStream *out, OpenTypeFile *file) { + if (!SerialiseMetricsTable(out, &file->vmtx->metrics)) { + return OTS_FAILURE(); + } + return true; +} + +void ots_vmtx_free(OpenTypeFile *file) { + delete file->vmtx; +} + +} // namespace ots + diff --git a/src/vmtx.h b/src/vmtx.h new file mode 100644 index 00000000..061dc73e --- /dev/null +++ b/src/vmtx.h @@ -0,0 +1,20 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef OTS_VMTX_H_ +#define OTS_VMTX_H_ + +#include "metrics.h" +#include "ots.h" + +namespace ots { + +struct OpenTypeVMTX { + OpenTypeMetricsTable metrics; +}; + +} // namespace ots + +#endif // OTS_VMTX_H_ + diff --git a/test/SConstruct b/test/SConstruct index 907dd915..157cec84 100644 --- a/test/SConstruct +++ b/test/SConstruct @@ -31,17 +31,21 @@ env.Library('../src/libots.a', '../src/loca.cc', '../src/ltsh.cc', '../src/maxp.cc', + '../src/metrics.cc', '../src/name.cc', '../src/os2.cc', '../src/ots.cc', '../src/post.cc', '../src/prep.cc', '../src/vdmx.cc', + '../src/vhea.cc', + '../src/vmtx.cc', '../src/vorg.cc' ]) env.Program('../test/cff_type2_charstring_test.cc', LIBS = ['ots', 'gtest_main'], LIBPATH = '../src') env.Program('../test/layout_common_table_test.cc', LIBS = ['ots', 'gtest_main'], LIBPATH = '../src') +env.Program('../test/table_dependencies_test.cc', LIBS = ['ots', 'gtest_main'], LIBPATH = '../src') env.Program('../test/ot-sanitise.cc', LIBS = ['ots'], LIBPATH='../src') env.Program('../test/idempotent.cc', LIBS = ['ots', 'freetype', 'z', 'm'], LIBPATH='../src') env.Program('../test/perf.cc', LIBS = ['ots'], LIBPATH='../src') diff --git a/test/table_dependencies_test.cc b/test/table_dependencies_test.cc new file mode 100644 index 00000000..bbaaa30b --- /dev/null +++ b/test/table_dependencies_test.cc @@ -0,0 +1,78 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include + +#include "gsub.h" +#include "ots.h" +#include "ots-memory-stream.h" +#include "vhea.h" +#include "vmtx.h" + +#define SET_TABLE(name, capname) \ + do { file.name = new ots::OpenType##capname; } while (0) +#define SET_LAYOUT_TABLE(name, capname) \ + do { \ + if (!file.name) { \ + SET_TABLE(name, capname); \ + } \ + file.name->data = reinterpret_cast(1); \ + file.name->length = 1; \ + } while (0) +#define DROP_TABLE(name) \ + do { delete file.name; file.name = NULL; } while (0) +#define DROP_LAYOUT_TABLE(name) \ + do { file.name->data = NULL; file.name->length = 0; } while (0) + +namespace { + +class TableDependenciesTest : public ::testing::Test { + protected: + virtual void SetUp() { + SET_LAYOUT_TABLE(gsub, GSUB); + SET_TABLE(vhea, VHEA); + SET_TABLE(vmtx, VMTX); + } + + virtual void TearDown() { + DROP_TABLE(gsub); + DROP_TABLE(vhea); + DROP_TABLE(vmtx); + } + ots::OpenTypeFile file; +}; +} // namespace + +TEST_F(TableDependenciesTest, TestVhea) { + EXPECT_TRUE(ots::ots_vhea_should_serialise(&file)); +} + +TEST_F(TableDependenciesTest, TestVmtx) { + EXPECT_TRUE(ots::ots_vmtx_should_serialise(&file)); +} + +TEST_F(TableDependenciesTest, TestVheaVmtx) { + DROP_TABLE(vmtx); + EXPECT_FALSE(ots::ots_vhea_should_serialise(&file)); +} + +TEST_F(TableDependenciesTest, TestVmtxVhea) { + DROP_TABLE(vhea); + EXPECT_FALSE(ots::ots_vmtx_should_serialise(&file)); +} + +TEST_F(TableDependenciesTest, TestVheaGsub) { + DROP_LAYOUT_TABLE(gsub); + EXPECT_FALSE(ots::ots_vhea_should_serialise(&file)); + DROP_TABLE(gsub); + EXPECT_FALSE(ots::ots_vhea_should_serialise(&file)); +} + +TEST_F(TableDependenciesTest, TestVmtxGsub) { + DROP_LAYOUT_TABLE(gsub); + EXPECT_FALSE(ots::ots_vmtx_should_serialise(&file)); + DROP_TABLE(gsub); + EXPECT_FALSE(ots::ots_vmtx_should_serialise(&file)); +} +