Merge m-c to fx-team.

This commit is contained in:
Ryan VanderMeulen 2014-01-31 16:59:29 -05:00
commit 4dd29179e9
87 changed files with 2778 additions and 1949 deletions

View File

@ -2835,8 +2835,8 @@ GetXPConnectNative(JSContext* aCx, JSObject* aObj) {
}
static nsresult
GetFileOrBlob(const nsAString& aName, const JS::Value& aBlobParts,
const JS::Value& aParameters, JSContext* aCx,
GetFileOrBlob(const nsAString& aName, JS::Handle<JS::Value> aBlobParts,
JS::Handle<JS::Value> aParameters, JSContext* aCx,
uint8_t aOptionalArgCount, nsISupports** aResult)
{
if (!nsContentUtils::IsCallerChrome()) {
@ -2858,9 +2858,12 @@ GetFileOrBlob(const nsAString& aName, const JS::Value& aBlobParts,
nsDOMMultipartFile* domFile =
static_cast<nsDOMMultipartFile*>(static_cast<nsIDOMFile*>(file.get()));
JS::Value args[2] = { aBlobParts, aParameters };
JS::AutoValueVector args(aCx);
MOZ_ALWAYS_TRUE(args.resize(2));
args[0] = aBlobParts;
args[1] = aParameters;
rv = domFile->InitBlob(aCx, aOptionalArgCount, args, GetXPConnectNative);
rv = domFile->InitBlob(aCx, aOptionalArgCount, args.begin(), GetXPConnectNative);
NS_ENSURE_SUCCESS(rv, rv);
file.forget(aResult);

View File

@ -909,7 +909,7 @@ CompositorOGL::CreateFBOWithTexture(const IntRect& aRect, bool aCopyFromSource,
mGLContext->fCopyTexImage2D(mFBOTextureTarget,
0,
LOCAL_GL_RGBA,
aRect.x, aRect.y,
aRect.x, FlipY(aRect.y + aRect.height),
aRect.width, aRect.height,
0);
} else {

View File

@ -1,14 +1,10 @@
This is the Sanitiser for OpenType project, from http://code.google.com/p/ots/.
Current revision: r95
Our reference repository is https://github.com/khaledhosny/ots/.
Current revision: d7d831edd171054c7974f5e0dec2fc19bf869574
Applied local patches:
ots-fix-vc10.patch - workaround for VS10 STL wrappers (bug 602558)
ots-fix-sparc64.patch - fix alignment error on sparc64 (bug 643137)
ots-graphite.patch - preserve Graphite layout tables (bug 631479)
ots-visibility.patch - make Process function externally visible for Windows DLL (bug 711079)
Patches from https://bugzilla.mozilla.org/show_bug.cgi?id=670901.
ots-woff2 - disable WOFF2 support (bug 941019)

View File

@ -44,7 +44,7 @@ typedef unsigned __int64 uint64_t;
#include <stdint.h>
#endif
#include <algorithm> // for std::min
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstring>
@ -81,9 +81,9 @@ class OTSStream {
}
if (chksum_buffer_offset_ == 4) {
uint32_t chksum;
std::memcpy(&chksum, chksum_buffer_, 4);
chksum_ += ntohl(chksum);
uint32_t tmp;
std::memcpy(&tmp, chksum_buffer_, 4);
chksum_ += ntohl(tmp);
chksum_buffer_offset_ = 0;
}
@ -199,13 +199,6 @@ class OTSStream {
unsigned chksum_buffer_offset_;
};
#ifdef MOZ_OTS_REPORT_ERRORS
// Signature of the function to be provided by the client in order to report errors.
// The return type is a boolean so that it can be used within an expression,
// but the actual value is ignored. (Suggested convention is to always return 'false'.)
typedef bool (*MessageFunc)(void *user_data, const char *format, ...);
#endif
// -----------------------------------------------------------------------------
// Process a given OpenType file and write out a sanitised version
// output: a pointer to an object implementing the OTSStream interface. The
@ -213,18 +206,46 @@ typedef bool (*MessageFunc)(void *user_data, const char *format, ...);
// partial output may have been written.
// input: the OpenType file
// length: the size, in bytes, of |input|
// preserve_graphite_tables: whether to preserve Graphite Layout tables
// -----------------------------------------------------------------------------
bool OTS_API Process(OTSStream *output, const uint8_t *input, size_t length,
#ifdef MOZ_OTS_REPORT_ERRORS
MessageFunc message_func, void *user_data,
bool OTS_API Process(OTSStream *output, const uint8_t *input, size_t length);
// Signature of the function to be provided by the client in order to report errors.
// The return type is a boolean so that it can be used within an expression,
// but the actual value is ignored. (Suggested convention is to always return 'false'.)
#ifdef __GCC__
#define MSGFUNC_FMT_ATTR __attribute__((format(printf, 2, 3)))
#else
#define MSGFUNC_FMT_ATTR
#endif
bool preserve_graphite_tables = false);
typedef bool (*MessageFunc)(void *user_data, const char *format, ...) MSGFUNC_FMT_ATTR;
// Set a callback function that will be called when OTS is reporting an error.
void OTS_API SetMessageCallback(MessageFunc func, void *user_data);
enum TableAction {
TABLE_ACTION_DEFAULT, // Use OTS's default action for that table
TABLE_ACTION_SANITIZE, // Sanitize the table, potentially droping it
TABLE_ACTION_PASSTHRU, // Serialize the table unchanged
TABLE_ACTION_DROP // Drop the table
};
// Signature of the function to be provided by the client to decide what action
// to do for a given table.
typedef TableAction (*TableActionFunc)(uint32_t tag, void *user_data);
// Set a callback function that will be called when OTS needs to decide what to
// do for a font table.
void OTS_API SetTableActionCallback(TableActionFunc func, void *user_data);
// Force to disable debug output even when the library is compiled with
// -DOTS_DEBUG.
void DisableDebugOutput();
#ifdef MOZ_OTS_WOFF2
// Enable WOFF2 support(experimental).
void EnableWOFF2();
#endif
} // namespace ots
#endif // OPENTYPE_SANITISER_H_

View File

@ -71,7 +71,7 @@ class ExpandingMemoryStream : public OTSStream {
if (new_length > limit_)
new_length = limit_;
uint8_t* new_buf = new uint8_t[new_length];
memcpy(new_buf, ptr_, length_);
std::memcpy(new_buf, ptr_, length_);
length_ = new_length;
delete[] static_cast<uint8_t*>(ptr_);
ptr_ = new_buf;

View File

@ -1,26 +0,0 @@
diff --git a/gfx/ots/include/opentype-sanitiser.h b/gfx/ots/include/opentype-sanitiser.h
--- a/gfx/ots/include/opentype-sanitiser.h
+++ b/gfx/ots/include/opentype-sanitiser.h
@@ -83,18 +83,20 @@ class OTSStream {
if (chksum_buffer_offset_ == 4) {
uint32_t chksum;
std::memcpy(&chksum, chksum_buffer_, 4);
chksum_ += ntohl(chksum);
chksum_buffer_offset_ = 0;
}
while (length >= 4) {
- chksum_ += ntohl(*reinterpret_cast<const uint32_t*>(
- reinterpret_cast<const uint8_t*>(data) + offset));
+ uint32_t tmp;
+ std::memcpy(&tmp, reinterpret_cast<const uint8_t *>(data) + offset,
+ sizeof(uint32_t));
+ chksum_ += ntohl(tmp);
length -= 4;
offset += 4;
}
if (length) {
if (chksum_buffer_offset_ != 0) return false; // not reached
if (length > 4) return false; // not reached
std::memcpy(chksum_buffer_,

View File

@ -1,60 +0,0 @@
diff --git a/gfx/ots/src/gasp.h b/gfx/ots/src/gasp.h
--- a/gfx/ots/src/gasp.h
+++ b/gfx/ots/src/gasp.h
@@ -1,15 +1,16 @@
// Copyright (c) 2009 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_GASP_H_
#define OTS_GASP_H_
+#include <new>
#include <utility> // std::pair
#include <vector>
#include "ots.h"
namespace ots {
struct OpenTypeGASP {
diff --git a/gfx/ots/src/glyf.h b/gfx/ots/src/glyf.h
--- a/gfx/ots/src/glyf.h
+++ b/gfx/ots/src/glyf.h
@@ -1,15 +1,16 @@
// Copyright (c) 2009 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_GLYF_H_
#define OTS_GLYF_H_
+#include <new>
#include <utility> // std::pair
#include <vector>
#include "ots.h"
namespace ots {
struct OpenTypeGLYF {
diff --git a/gfx/ots/src/metrics.h b/gfx/ots/src/metrics.h
--- a/gfx/ots/src/metrics.h
+++ b/gfx/ots/src/metrics.h
@@ -1,15 +1,16 @@
// 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 <new>
#include <utility> // std::pair
#include <vector>
#include "ots.h"
namespace ots {
struct OpenTypeMetricsHeader {

View File

@ -1,131 +0,0 @@
diff --git a/gfx/ots/include/opentype-sanitiser.h b/gfx/ots/include/opentype-sanitiser.h
--- a/gfx/ots/include/opentype-sanitiser.h
+++ b/gfx/ots/include/opentype-sanitiser.h
@@ -176,18 +176,20 @@ class OTSStream {
// -----------------------------------------------------------------------------
// Process a given OpenType file and write out a sanitised version
// output: a pointer to an object implementing the OTSStream interface. The
// sanitisied output will be written to this. In the even of a failure,
// partial output may have been written.
// input: the OpenType file
// length: the size, in bytes, of |input|
+// preserve_graphite_tables: whether to preserve Graphite Layout tables
// -----------------------------------------------------------------------------
-bool Process(OTSStream *output, const uint8_t *input, size_t length);
+bool Process(OTSStream *output, const uint8_t *input, size_t length,
+ bool preserve_graphite_tables = false);
// Force to disable debug output even when the library is compiled with
// -DOTS_DEBUG.
void DisableDebugOutput();
} // namespace ots
#endif // OPENTYPE_SANITISER_H_
diff --git a/gfx/ots/src/ots.cc b/gfx/ots/src/ots.cc
--- a/gfx/ots/src/ots.cc
+++ b/gfx/ots/src/ots.cc
@@ -138,16 +138,27 @@ const struct {
{ "GPOS", ots::ots_gpos_parse, ots::ots_gpos_serialise,
ots::ots_gpos_should_serialise, ots::ots_gpos_free, false },
{ "GSUB", ots::ots_gsub_parse, ots::ots_gsub_serialise,
ots::ots_gsub_should_serialise, ots::ots_gsub_free, false },
{ "vhea", ots::ots_vhea_parse, ots::ots_vhea_serialise,
ots::ots_vhea_should_serialise, ots::ots_vhea_free, false },
{ "vmtx", ots::ots_vmtx_parse, ots::ots_vmtx_serialise,
ots::ots_vmtx_should_serialise, ots::ots_vmtx_free, false },
+ // SILGraphite layout tables - not actually parsed, just copied
+ { "Silf", ots::ots_silf_parse, ots::ots_silf_serialise,
+ ots::ots_silf_should_serialise, ots::ots_silf_free, false },
+ { "Sill", ots::ots_sill_parse, ots::ots_sill_serialise,
+ ots::ots_sill_should_serialise, ots::ots_sill_free, false },
+ { "Gloc", ots::ots_gloc_parse, ots::ots_gloc_serialise,
+ ots::ots_gloc_should_serialise, ots::ots_gloc_free, false },
+ { "Glat", ots::ots_glat_parse, ots::ots_glat_serialise,
+ ots::ots_glat_should_serialise, ots::ots_glat_free, false },
+ { "Feat", ots::ots_feat_parse, ots::ots_feat_serialise,
+ ots::ots_feat_should_serialise, ots::ots_feat_free, false },
// TODO(bashi): Support mort, base, and jstf tables.
{ 0, NULL, NULL, NULL, NULL, false },
};
bool IsValidVersionTag(uint32_t tag) {
return tag == Tag("\x00\x01\x00\x00") ||
// OpenType fonts with CFF data have 'OTTO' tag.
tag == Tag("OTTO") ||
@@ -581,22 +592,25 @@ bool ProcessGeneric(ots::OpenTypeFile *h
} // namespace
namespace ots {
void DisableDebugOutput() {
g_debug_output = false;
}
-bool Process(OTSStream *output, const uint8_t *data, size_t length) {
+bool Process(OTSStream *output, const uint8_t *data, size_t length,
+ bool preserveGraphite) {
OpenTypeFile header;
if (length < 4) {
return OTS_FAILURE();
}
+ header.preserve_graphite = preserveGraphite;
+
bool result;
if (data[0] == 'w' && data[1] == 'O' && data[2] == 'F' && data[3] == 'F') {
result = ProcessWOFF(&header, output, data, length);
} else {
result = ProcessTTF(&header, output, data, length);
}
for (unsigned i = 0; ; ++i) {
diff --git a/gfx/ots/src/ots.h b/gfx/ots/src/ots.h
--- a/gfx/ots/src/ots.h
+++ b/gfx/ots/src/ots.h
@@ -178,17 +178,22 @@ class Buffer {
F(maxp, MAXP) \
F(name, NAME) \
F(os2, OS2) \
F(post, POST) \
F(prep, PREP) \
F(vdmx, VDMX) \
F(vorg, VORG) \
F(vhea, VHEA) \
- F(vmtx, VMTX)
+ F(vmtx, VMTX) \
+ F(silf, SILF) \
+ F(sill, SILL) \
+ F(glat, GLAT) \
+ F(gloc, GLOC) \
+ F(feat, FEAT)
#define F(name, capname) struct OpenType##capname;
FOR_EACH_TABLE_TYPE
#undef F
struct OpenTypeFile {
OpenTypeFile() {
#define F(name, capname) name = NULL;
@@ -197,16 +202,20 @@ struct OpenTypeFile {
}
uint32_t version;
uint16_t num_tables;
uint16_t search_range;
uint16_t entry_selector;
uint16_t range_shift;
+ // This is used to tell the relevant parsers whether to preserve the
+ // Graphite layout tables (currently _without_ any checking)
+ bool preserve_graphite;
+
#define F(name, capname) OpenType##capname *name;
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); \

View File

@ -37,24 +37,52 @@ diff --git a/gfx/ots/include/opentype-sanitiser.h b/gfx/ots/include/opentype-san
typedef unsigned short uint16_t;
typedef int int32_t;
typedef unsigned int uint32_t;
@@ -178,18 +198,18 @@ class OTSStream {
@@ -182,45 +202,45 @@ class OTSStream {
// -----------------------------------------------------------------------------
// Process a given OpenType file and write out a sanitised version
// output: a pointer to an object implementing the OTSStream interface. The
// sanitisied output will be written to this. In the even of a failure,
// partial output may have been written.
// input: the OpenType file
// length: the size, in bytes, of |input|
// preserve_graphite_tables: whether to preserve Graphite Layout tables
// -----------------------------------------------------------------------------
-bool Process(OTSStream *output, const uint8_t *input, size_t length,
- bool preserve_graphite_tables = false);
+bool OTS_API Process(OTSStream *output, const uint8_t *input, size_t length,
+ bool preserve_graphite_tables = false);
-bool Process(OTSStream *output, const uint8_t *input, size_t length);
+bool OTS_API Process(OTSStream *output, const uint8_t *input, size_t length);
// Signature of the function to be provided by the client in order to report errors.
// The return type is a boolean so that it can be used within an expression,
// but the actual value is ignored. (Suggested convention is to always return 'false'.)
#ifdef __GCC__
#define MSGFUNC_FMT_ATTR __attribute__((format(printf, 2, 3)))
#else
#define MSGFUNC_FMT_ATTR
#endif
typedef bool (*MessageFunc)(void *user_data, const char *format, ...) MSGFUNC_FMT_ATTR;
// Set a callback function that will be called when OTS is reporting an error.
-void SetMessageCallback(MessageFunc func, void *user_data);
+void OTS_API SetMessageCallback(MessageFunc func, void *user_data);
enum TableAction {
TABLE_ACTION_DEFAULT, // Use OTS's default action for that table
TABLE_ACTION_SANITIZE, // Sanitize the table, potentially droping it
TABLE_ACTION_PASSTHRU, // Serialize the table unchanged
TABLE_ACTION_DROP // Drop the table
};
// Signature of the function to be provided by the client to decide what action
// to do for a given table.
typedef TableAction (*TableActionFunc)(uint32_t tag, void *user_data);
// Set a callback function that will be called when OTS needs to decide what to
// do for a font table.
-void SetTableActionCallback(TableActionFunc func, void *user_data);
+void OTS_API SetTableActionCallback(TableActionFunc func, void *user_data);
// Force to disable debug output even when the library is compiled with
// -DOTS_DEBUG.
void DisableDebugOutput();
} // namespace ots
// Enable WOFF2 support(experimental).
void EnableWOFF2();
#endif // OPENTYPE_SANITISER_H_

134
gfx/ots/ots-woff2.patch Normal file
View File

@ -0,0 +1,134 @@
diff --git a/gfx/ots/include/opentype-sanitiser.h b/gfx/ots/include/opentype-sanitiser.h
--- a/gfx/ots/include/opentype-sanitiser.h
+++ b/gfx/ots/include/opentype-sanitiser.h
@@ -236,14 +236,16 @@ typedef TableAction (*TableActionFunc)(u
// Set a callback function that will be called when OTS needs to decide what to
// do for a font table.
void OTS_API SetTableActionCallback(TableActionFunc func, void *user_data);
// Force to disable debug output even when the library is compiled with
// -DOTS_DEBUG.
void DisableDebugOutput();
+#ifdef MOZ_OTS_WOFF2
// Enable WOFF2 support(experimental).
void EnableWOFF2();
+#endif
} // namespace ots
#endif // OPENTYPE_SANITISER_H_
diff --git a/gfx/ots/src/ots.cc b/gfx/ots/src/ots.cc
--- a/gfx/ots/src/ots.cc
+++ b/gfx/ots/src/ots.cc
@@ -9,25 +9,29 @@
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <limits>
#include <map>
#include <vector>
+#ifdef MOZ_OTS_WOFF2
#include "woff2.h"
+#endif
// The OpenType Font File
// http://www.microsoft.com/typography/otspec/cmap.htm
namespace {
bool g_debug_output = true;
+#ifdef MOZ_OTS_WOFF2
bool g_enable_woff2 = false;
+#endif
ots::MessageFunc g_message_func = NULL;
void *g_message_user_data = NULL;
ots::TableActionFunc g_table_action_func = NULL;
void *g_table_action_user_data = NULL;
// Generate a message with or without a table tag, when 'header' is the OpenTypeFile pointer
@@ -395,16 +399,17 @@ bool ProcessWOFF(ots::OpenTypeFile *head
}
if (block_end != ots::Round4(length)) {
return OTS_FAILURE_MSG_HDR("file length mismatch (trailing junk?)");
}
return ProcessGeneric(header, woff_tag, output, data, length, tables, file);
}
+#ifdef MOZ_OTS_WOFF2
bool ProcessWOFF2(ots::OpenTypeFile *header,
ots::OTSStream *output, const uint8_t *data, size_t length) {
size_t decompressed_size = ots::ComputeWOFF2FinalSize(data, length);
if (decompressed_size == 0) {
return OTS_FAILURE();
}
// decompressed font must be <= 30MB
if (decompressed_size > 30 * 1024 * 1024) {
@@ -413,16 +418,17 @@ bool ProcessWOFF2(ots::OpenTypeFile *hea
std::vector<uint8_t> decompressed_buffer(decompressed_size);
if (!ots::ConvertWOFF2ToTTF(&decompressed_buffer[0], decompressed_size,
data, length)) {
return OTS_FAILURE();
}
return ProcessTTF(header, output, &decompressed_buffer[0], decompressed_size);
}
+#endif
ots::TableAction GetTableAction(uint32_t tag) {
ots::TableAction action = ots::TABLE_ACTION_DEFAULT;
if (g_table_action_func != NULL) {
action = g_table_action_func(htonl(tag), g_table_action_user_data);
}
@@ -795,19 +801,21 @@ bool IsValidVersionTag(uint32_t tag) {
tag == Tag("true") ||
tag == Tag("typ1");
}
void DisableDebugOutput() {
g_debug_output = false;
}
+#ifdef MOZ_OTS_WOFF2
void EnableWOFF2() {
g_enable_woff2 = true;
}
+#endif
void SetMessageCallback(MessageFunc func, void *user_data) {
g_message_func = func;
g_message_user_data = user_data;
}
void SetTableActionCallback(TableActionFunc func, void *user_data) {
g_table_action_func = func;
@@ -822,20 +830,22 @@ bool Process(OTSStream *output, const ui
if (length < 4) {
return OTS_FAILURE_MSG_(&header, "file less than 4 bytes");
}
bool result;
if (data[0] == 'w' && data[1] == 'O' && data[2] == 'F' && data[3] == 'F') {
result = ProcessWOFF(&header, output, data, length);
+#ifdef MOZ_OTS_WOFF2
} else if (g_enable_woff2 &&
data[0] == 'w' && data[1] == 'O' && data[2] == 'F' &&
data[3] == '2') {
result = ProcessWOFF2(&header, output, data, length);
+#endif
} else {
result = ProcessTTF(&header, output, data, length);
}
for (unsigned i = 0; ; ++i) {
if (table_parsers[i].parse == NULL) break;
table_parsers[i].free(&header);
}

View File

@ -5,7 +5,7 @@
#include "cff.h"
#include <cstring>
#include <utility> // std::pair
#include <utility>
#include <vector>
#include "cff_type2_charstring.h"
@ -14,6 +14,8 @@
// http://www.microsoft.com/typography/otspec/cff.htm
// http://www.microsoft.com/typography/otspec/cffspec.htm
#define TABLE_NAME "CFF"
namespace {
enum DICT_OPERAND_TYPE {
@ -415,8 +417,8 @@ bool ParsePrivateDictData(
return OTS_FAILURE();
}
// parse "16. Local Subrs INDEX"
ots::Buffer table(data, table_length);
table.set_offset(operands.back().first + offset);
ots::Buffer cff_table(data, table_length);
cff_table.set_offset(operands.back().first + offset);
ots::CFFIndex *local_subrs_index = NULL;
if (type == DICT_DATA_FDARRAY) {
if (out_cff->local_subrs_per_font.empty()) {
@ -430,7 +432,7 @@ bool ParsePrivateDictData(
local_subrs_index = new ots::CFFIndex;
out_cff->local_subrs = local_subrs_index;
}
if (!ParseIndex(&table, local_subrs_index)) {
if (!ParseIndex(&cff_table, local_subrs_index)) {
return OTS_FAILURE();
}
break;
@ -602,10 +604,10 @@ bool ParseDictData(const uint8_t *data, size_t table_length,
}
// parse sub dictionary INDEX.
ots::Buffer table(data, table_length);
table.set_offset(operands.back().first);
ots::Buffer cff_table(data, table_length);
cff_table.set_offset(operands.back().first);
uint8_t format = 0;
if (!table.ReadU8(&format)) {
if (!cff_table.ReadU8(&format)) {
return OTS_FAILURE();
}
if (format & 0x80) {
@ -627,10 +629,10 @@ bool ParseDictData(const uint8_t *data, size_t table_length,
return OTS_FAILURE();
}
// parse "14. CharStrings INDEX"
ots::Buffer table(data, table_length);
table.set_offset(operands.back().first);
ots::Buffer cff_table(data, table_length);
cff_table.set_offset(operands.back().first);
ots::CFFIndex *charstring_index = out_cff->char_strings_array.back();
if (!ParseIndex(&table, charstring_index)) {
if (!ParseIndex(&cff_table, charstring_index)) {
return OTS_FAILURE();
}
if (charstring_index->count < 2) {
@ -655,10 +657,10 @@ bool ParseDictData(const uint8_t *data, size_t table_length,
}
// parse sub dictionary INDEX.
ots::Buffer table(data, table_length);
table.set_offset(operands.back().first);
ots::Buffer cff_table(data, table_length);
cff_table.set_offset(operands.back().first);
ots::CFFIndex sub_dict_index;
if (!ParseIndex(&table, &sub_dict_index)) {
if (!ParseIndex(&cff_table, &sub_dict_index)) {
return OTS_FAILURE();
}
if (!ParseDictData(data, table_length,
@ -685,23 +687,23 @@ bool ParseDictData(const uint8_t *data, size_t table_length,
}
// parse FDSelect data structure
ots::Buffer table(data, table_length);
table.set_offset(operands.back().first);
ots::Buffer cff_table(data, table_length);
cff_table.set_offset(operands.back().first);
uint8_t format = 0;
if (!table.ReadU8(&format)) {
if (!cff_table.ReadU8(&format)) {
return OTS_FAILURE();
}
if (format == 0) {
for (size_t j = 0; j < glyphs; ++j) {
uint8_t fd_index = 0;
if (!table.ReadU8(&fd_index)) {
if (!cff_table.ReadU8(&fd_index)) {
return OTS_FAILURE();
}
(out_cff->fd_select)[j] = fd_index;
}
} else if (format == 3) {
uint16_t n_ranges = 0;
if (!table.ReadU16(&n_ranges)) {
if (!cff_table.ReadU16(&n_ranges)) {
return OTS_FAILURE();
}
if (n_ranges == 0) {
@ -712,7 +714,7 @@ bool ParseDictData(const uint8_t *data, size_t table_length,
uint8_t fd_index = 0;
for (unsigned j = 0; j < n_ranges; ++j) {
uint16_t first = 0; // GID
if (!table.ReadU16(&first)) {
if (!cff_table.ReadU16(&first)) {
return OTS_FAILURE();
}
@ -734,14 +736,14 @@ bool ParseDictData(const uint8_t *data, size_t table_length,
}
}
if (!table.ReadU8(&fd_index)) {
if (!cff_table.ReadU8(&fd_index)) {
return OTS_FAILURE();
}
last_gid = first;
// TODO(yusukes): check GID?
}
uint16_t sentinel = 0;
if (!table.ReadU16(&sentinel)) {
if (!cff_table.ReadU16(&sentinel)) {
return OTS_FAILURE();
}
if (last_gid >= sentinel) {
@ -828,17 +830,17 @@ bool ParseDictData(const uint8_t *data, size_t table_length,
// parse "13. Charsets"
if (charset_offset) {
ots::Buffer table(data, table_length);
table.set_offset(charset_offset);
ots::Buffer cff_table(data, table_length);
cff_table.set_offset(charset_offset);
uint8_t format = 0;
if (!table.ReadU8(&format)) {
if (!cff_table.ReadU8(&format)) {
return OTS_FAILURE();
}
switch (format) {
case 0:
for (unsigned j = 1 /* .notdef is omitted */; j < glyphs; ++j) {
uint16_t sid = 0;
if (!table.ReadU16(&sid)) {
if (!cff_table.ReadU16(&sid)) {
return OTS_FAILURE();
}
if (!have_ros && (sid > sid_max)) {
@ -853,7 +855,7 @@ bool ParseDictData(const uint8_t *data, size_t table_length,
uint32_t total = 1; // .notdef is omitted.
while (total < glyphs) {
uint16_t sid = 0;
if (!table.ReadU16(&sid)) {
if (!cff_table.ReadU16(&sid)) {
return OTS_FAILURE();
}
if (!have_ros && (sid > sid_max)) {
@ -863,13 +865,13 @@ bool ParseDictData(const uint8_t *data, size_t table_length,
if (format == 1) {
uint8_t left = 0;
if (!table.ReadU8(&left)) {
if (!cff_table.ReadU8(&left)) {
return OTS_FAILURE();
}
total += (left + 1);
} else {
uint16_t left = 0;
if (!table.ReadU16(&left)) {
if (!cff_table.ReadU16(&left)) {
return OTS_FAILURE();
}
total += (left + 1);

View File

@ -38,6 +38,7 @@ bool ExecuteType2CharString(size_t call_depth,
bool *out_found_width,
size_t *in_out_num_stems);
#ifdef DUMP_T2CHARSTRING
// Converts |op| to a string and returns it.
const char *Type2CharStringOperatorToString(ots::Type2CharStringOperator op) {
switch (op) {
@ -87,6 +88,8 @@ const char *Type2CharStringOperatorToString(ots::Type2CharStringOperator op) {
return "VHCurveTo";
case ots::kHVCurveTo:
return "HVCurveTo";
case ots::kDotSection:
return "DotSection";
case ots::kAnd:
return "And";
case ots::kOr:
@ -139,6 +142,7 @@ const char *Type2CharStringOperatorToString(ots::Type2CharStringOperator op) {
return "UNKNOWN";
}
#endif
// Read one or more bytes from the |char_string| buffer and stores the number
// read on |out_number|. If the number read is an operator (ex 'vstem'), sets
@ -524,6 +528,13 @@ bool ExecuteType2CharStringOperator(int32_t op,
return successful ? true : OTS_FAILURE();
}
case ots::kDotSection:
// Deprecated operator but harmless, we probably should drop it some how.
if (stack_size != 0) {
return OTS_FAILURE();
}
return true;
case ots::kAnd:
case ots::kOr:
case ots::kEq:
@ -738,19 +749,21 @@ bool ExecuteType2CharString(size_t call_depth,
return OTS_FAILURE();
}
#ifdef DUMP_T2CHARSTRING
/*
You can dump all operators and operands (except mask bytes for hintmask
and cntrmask) by the following code:
*/
if (!is_operator) {
std::fprintf(stderr, "#%d# ", operator_or_operand);
} else {
std::fprintf(stderr, "#%s#\n",
Type2CharStringOperatorToString(
Type2CharStringOperator(operator_or_operand)),
operator_or_operand);
ots::Type2CharStringOperator(operator_or_operand))
);
}
*/
#endif
if (!is_operator) {
argument_stack->push(operator_or_operand);

View File

@ -67,6 +67,7 @@ enum Type2CharStringOperator {
kCallGSubr = 29,
kVHCurveTo = 30,
kHVCurveTo = 31,
kDotSection = 12 << 8,
kAnd = (12 << 8) + 3,
kOr = (12 << 8) + 4,
kNot = (12 << 8) + 5,
@ -91,8 +92,7 @@ enum Type2CharStringOperator {
kFlex = (12 << 8) + 35,
kHFlex1 = (12 << 8) + 36,
kFlex1 = (12 << 8) + 37,
// Operators that are obsoleted or undocumented, such as 'blend', will be
// rejected.
// Operators that are undocumented, such as 'blend', will be rejected.
};
} // namespace ots

View File

@ -13,7 +13,9 @@
#include "os2.h"
// cmap - Character To Glyph Index Mapping Table
// http://www.microsoft.com/opentype/otspec/cmap.htm
// http://www.microsoft.com/typography/otspec/cmap.htm
#define TABLE_NAME "cmap"
namespace {
@ -23,6 +25,7 @@ struct CMAPSubtableHeader {
uint32_t offset;
uint16_t format;
uint32_t length;
uint32_t language;
};
struct Subtable314Range {
@ -67,19 +70,19 @@ bool ParseFormat4(ots::OpenTypeFile *file, int platform, int encoding,
// in the output.
if (!file->os2) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Required OS/2 table missing");
}
if (!subtable.Skip(4)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read 4 bytes at start of cmap format 4 subtable");
}
uint16_t language = 0;
if (!subtable.ReadU16(&language)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read language");
}
if (language) {
// Platform ID 3 (windows) subtables should have language '0'.
return OTS_FAILURE();
return OTS_FAILURE_MSG("Languages should be 0 (%d)", language);
}
uint16_t segcountx2, search_range, entry_selector, range_shift;
@ -88,16 +91,16 @@ bool ParseFormat4(ots::OpenTypeFile *file, int platform, int encoding,
!subtable.ReadU16(&search_range) ||
!subtable.ReadU16(&entry_selector) ||
!subtable.ReadU16(&range_shift)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read subcmap structure");
}
if (segcountx2 & 1 || search_range & 1) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad subcmap structure");
}
const uint16_t segcount = segcountx2 >> 1;
// There must be at least one segment according the spec.
if (segcount < 1) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Segcount < 1 (%d)", segcount);
}
// log2segcount is the maximal x s.t. 2^x < segcount
@ -108,48 +111,48 @@ bool ParseFormat4(ots::OpenTypeFile *file, int platform, int encoding,
const uint16_t expected_search_range = 2 * 1u << log2segcount;
if (expected_search_range != search_range) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("expected search range != search range (%d != %d)", expected_search_range, search_range);
}
if (entry_selector != log2segcount) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("entry selector != log2(segement count) (%d != %d)", entry_selector, log2segcount);
}
const uint16_t expected_range_shift = segcountx2 - search_range;
if (range_shift != expected_range_shift) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("unexpected range shift (%d != %d)", range_shift, expected_range_shift);
}
std::vector<Subtable314Range> ranges(segcount);
for (unsigned i = 0; i < segcount; ++i) {
if (!subtable.ReadU16(&ranges[i].end_range)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read segment %d", i);
}
}
uint16_t padding;
if (!subtable.ReadU16(&padding)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read cmap subtable segment padding");
}
if (padding) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Non zero cmap subtable segment padding (%d)", padding);
}
for (unsigned i = 0; i < segcount; ++i) {
if (!subtable.ReadU16(&ranges[i].start_range)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read segment start range %d", i);
}
}
for (unsigned i = 0; i < segcount; ++i) {
if (!subtable.ReadS16(&ranges[i].id_delta)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read segment delta %d", i);
}
}
for (unsigned i = 0; i < segcount; ++i) {
ranges[i].id_range_offset_offset = subtable.offset();
if (!subtable.ReadU16(&ranges[i].id_range_offset)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read segment range offset %d", i);
}
if (ranges[i].id_range_offset & 1) {
@ -162,7 +165,7 @@ bool ParseFormat4(ots::OpenTypeFile *file, int platform, int encoding,
// The id_range_offset value in the transcoded font will not change
// since this table is not actually "transcoded" yet.
} else {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad segment offset (%d)", ranges[i].id_range_offset);
}
}
}
@ -184,10 +187,10 @@ bool ParseFormat4(ots::OpenTypeFile *file, int platform, int encoding,
// Note: some Linux fonts (e.g., LucidaSansOblique.ttf, bsmi00lp.ttf) have
// unsorted table...
if (ranges[i].end_range <= ranges[i - 1].end_range) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Out of order end range (%d <= %d)", ranges[i].end_range, ranges[i-1].end_range);
}
if (ranges[i].start_range <= ranges[i - 1].end_range) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("out of order start range (%d <= %d)", ranges[i].start_range, ranges[i-1].end_range);
}
// On many fonts, the value of {first, last}_char_index are incorrect.
@ -205,8 +208,9 @@ bool ParseFormat4(ots::OpenTypeFile *file, int platform, int encoding,
}
// The last range must end at 0xffff
if (ranges[segcount - 1].end_range != 0xffff) {
return OTS_FAILURE();
if (ranges[segcount - 1].start_range != 0xffff || ranges[segcount - 1].end_range != 0xffff) {
return OTS_FAILURE_MSG("Final segment start and end must be 0xFFFF (0x%04X-0x%04X)",
ranges[segcount - 1].start_range, ranges[segcount - 1].end_range);
}
// A format 4 CMAP subtable is complex. To be safe we simulate a lookup of
@ -219,7 +223,7 @@ bool ParseFormat4(ots::OpenTypeFile *file, int platform, int encoding,
// this is explictly allowed to overflow in the spec
const uint16_t glyph = code_point + ranges[i].id_delta;
if (glyph >= num_glyphs) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Range glyph reference too high (%d > %d)", glyph, num_glyphs - 1);
}
} else {
const uint16_t range_delta = code_point - ranges[i].start_range;
@ -230,13 +234,13 @@ bool ParseFormat4(ots::OpenTypeFile *file, int platform, int encoding,
range_delta * 2;
// We need to be able to access a 16-bit value from this offset
if (glyph_id_offset + 1 >= length) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("bad glyph id offset (%d > %ld)", glyph_id_offset, length);
}
uint16_t glyph;
memcpy(&glyph, data + glyph_id_offset, 2);
std::memcpy(&glyph, data + glyph_id_offset, 2);
glyph = ntohs(glyph);
if (glyph >= num_glyphs) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Range glyph reference too high (%d > %d)", glyph, num_glyphs - 1);
}
}
}
@ -254,7 +258,7 @@ bool ParseFormat4(ots::OpenTypeFile *file, int platform, int encoding,
file->cmap->subtable_0_3_4_data = data;
file->cmap->subtable_0_3_4_length = length;
} else {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Unknown cmap subtable type (platform=%d, encoding=%d)", platform, encoding);
}
return true;
@ -268,22 +272,22 @@ bool Parse31012(ots::OpenTypeFile *file,
// later.
if (!subtable.Skip(8)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("failed to skip the first 8 bytes of format 12 subtable");
}
uint32_t language = 0;
if (!subtable.ReadU32(&language)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("can't read format 12 subtable language");
}
if (language) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("format 12 subtable language should be zero (%d)", language);
}
uint32_t num_groups = 0;
if (!subtable.ReadU32(&num_groups)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("can't read number of format 12 subtable groups");
}
if (num_groups == 0 || num_groups > kMaxCMAPGroups) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("bad format 12 subtable group count %d", num_groups);
}
std::vector<ots::OpenTypeCMAPSubtableRange> &groups
@ -294,47 +298,52 @@ bool Parse31012(ots::OpenTypeFile *file,
if (!subtable.ReadU32(&groups[i].start_range) ||
!subtable.ReadU32(&groups[i].end_range) ||
!subtable.ReadU32(&groups[i].start_glyph_id)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("can't read format 12 subtable group");
}
if (groups[i].start_range > kUnicodeUpperLimit ||
groups[i].end_range > kUnicodeUpperLimit ||
groups[i].start_glyph_id > 0xFFFF) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("bad format 12 subtable group (startCharCode=0x%4X, endCharCode=0x%4X, startGlyphID=%d)",
groups[i].start_range, groups[i].end_range, groups[i].start_glyph_id);
}
// [0xD800, 0xDFFF] are surrogate code points.
if (groups[i].start_range >= 0xD800 &&
groups[i].start_range <= 0xDFFF) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("format 12 subtable out of range group startCharCode (0x%4X)", groups[i].start_range);
}
if (groups[i].end_range >= 0xD800 &&
groups[i].end_range <= 0xDFFF) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("format 12 subtable out of range group endCharCode (0x%4X)", groups[i].end_range);
}
if (groups[i].start_range < 0xD800 &&
groups[i].end_range > 0xDFFF) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("bad format 12 subtable group startCharCode (0x%4X) or endCharCode (0x%4X)",
groups[i].start_range, groups[i].end_range);
}
// We assert that the glyph value is within range. Because of the range
// limits, above, we don't need to worry about overflow.
if (groups[i].end_range < groups[i].start_range) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("format 12 subtable group endCharCode before startCharCode (0x%4X < 0x%4X)",
groups[i].end_range, groups[i].start_range);
}
if ((groups[i].end_range - groups[i].start_range) +
groups[i].start_glyph_id > num_glyphs) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("bad format 12 subtable group startGlyphID (%d)", groups[i].start_glyph_id);
}
}
// the groups must be sorted by start code and may not overlap
for (unsigned i = 1; i < num_groups; ++i) {
if (groups[i].start_range <= groups[i - 1].start_range) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("out of order format 12 subtable group (startCharCode=0x%4X <= startCharCode=0x%4X of previous group)",
groups[i].start_range, groups[i-1].start_range);
}
if (groups[i].start_range <= groups[i - 1].end_range) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("overlapping format 12 subtable groups (startCharCode=0x%4X <= endCharCode=0x%4X of previous group)",
groups[i].start_range, groups[i-1].end_range);
}
}
@ -349,25 +358,25 @@ bool Parse31013(ots::OpenTypeFile *file,
// later.
if (!subtable.Skip(8)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad cmap subtable length");
}
uint16_t language = 0;
if (!subtable.ReadU16(&language)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read cmap subtable language");
}
if (language) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Cmap subtable language should be zero but is %d", language);
}
uint32_t num_groups = 0;
if (!subtable.ReadU32(&num_groups)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read number of groups in a cmap subtable");
}
// We limit the number of groups in the same way as in 3.10.12 tables. See
// the comment there in
if (num_groups == 0 || num_groups > kMaxCMAPGroups) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad number of groups (%d) in a cmap subtable", num_groups);
}
std::vector<ots::OpenTypeCMAPSubtableRange> &groups
@ -378,7 +387,7 @@ bool Parse31013(ots::OpenTypeFile *file,
if (!subtable.ReadU32(&groups[i].start_range) ||
!subtable.ReadU32(&groups[i].end_range) ||
!subtable.ReadU32(&groups[i].start_glyph_id)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read subrange structure in a cmap subtable");
}
// We conservatively limit all of the values to protect some parsers from
@ -386,21 +395,21 @@ bool Parse31013(ots::OpenTypeFile *file,
if (groups[i].start_range > kUnicodeUpperLimit ||
groups[i].end_range > kUnicodeUpperLimit ||
groups[i].start_glyph_id > 0xFFFF) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad subrange with start_range=%d, end_range=%d, start_glyph_id=%d", groups[i].start_range, groups[i].end_range, groups[i].start_glyph_id);
}
if (groups[i].start_glyph_id >= num_glyphs) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Subrange starting glyph id too high (%d > %d)", groups[i].start_glyph_id, num_glyphs);
}
}
// the groups must be sorted by start code and may not overlap
for (unsigned i = 1; i < num_groups; ++i) {
if (groups[i].start_range <= groups[i - 1].start_range) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Overlapping subrange starts (%d >= %d)", groups[i]. start_range, groups[i-1].start_range);
}
if (groups[i].start_range <= groups[i - 1].end_range) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Overlapping subranges (%d <= %d)", groups[i].start_range, groups[i-1].end_range);
}
}
@ -417,15 +426,15 @@ bool Parse0514(ots::OpenTypeFile *file,
// Skip format (USHORT) and length (ULONG)
if (!subtable.Skip(6)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read start of cmap subtable");
}
uint32_t num_records = 0;
if (!subtable.ReadU32(&num_records)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read number of records in cmap subtable");
}
if (num_records == 0 || num_records > kMaxCMAPSelectorRecords) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad number of records (%d) in cmap subtable", num_records);
}
std::vector<ots::OpenTypeCMAPSubtableVSRecord>& records
@ -436,7 +445,7 @@ bool Parse0514(ots::OpenTypeFile *file,
if (!subtable.ReadU24(&records[i].var_selector) ||
!subtable.ReadU32(&records[i].default_offset) ||
!subtable.ReadU32(&records[i].non_default_offset)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read record structure of record %d in cmap subtale", i);
}
// Checks the value of variation selector
if (!((records[i].var_selector >= kMongolianVSStart &&
@ -445,24 +454,24 @@ bool Parse0514(ots::OpenTypeFile *file,
records[i].var_selector <= kVSEnd) ||
(records[i].var_selector >= kIVSStart &&
records[i].var_selector <= kIVSEnd))) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad record variation selector (%04X) in record %i", records[i].var_selector, i);
}
if (i > 0 &&
records[i-1].var_selector >= records[i].var_selector) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Out of order variation selector (%04X >= %04X) in record %d", records[i-1].var_selector, records[i].var_selector, i);
}
// Checks offsets
if (!records[i].default_offset && !records[i].non_default_offset) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("No default aoffset in variation selector record %d", i);
}
if (records[i].default_offset &&
records[i].default_offset >= length) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Default offset too high (%d >= %ld) in record %d", records[i].default_offset, length, i);
}
if (records[i].non_default_offset &&
records[i].non_default_offset >= length) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Non default offset too high (%d >= %ld) in record %d", records[i].non_default_offset, length, i);
}
}
@ -472,10 +481,10 @@ bool Parse0514(ots::OpenTypeFile *file,
subtable.set_offset(records[i].default_offset);
uint32_t num_ranges = 0;
if (!subtable.ReadU32(&num_ranges)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read number of ranges in record %d", i);
}
if (!num_ranges || num_ranges > kMaxCMAPGroups) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("number of ranges too high (%d > %d) in record %d", num_ranges, kMaxCMAPGroups, i);
}
uint32_t last_unicode_value = 0;
@ -486,7 +495,7 @@ bool Parse0514(ots::OpenTypeFile *file,
for (unsigned j = 0; j < num_ranges; ++j) {
if (!subtable.ReadU24(&ranges[j].unicode_value) ||
!subtable.ReadU8(&ranges[j].additional_count)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read range info in variation selector record %d", i);
}
const uint32_t check_value =
ranges[j].unicode_value + ranges[j].additional_count;
@ -495,7 +504,7 @@ bool Parse0514(ots::OpenTypeFile *file,
check_value > kUVSUpperLimit ||
(last_unicode_value &&
ranges[j].unicode_value <= last_unicode_value)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad Unicode value *%04X) in variation selector range %d record %d", ranges[j].unicode_value, j, i);
}
last_unicode_value = check_value;
}
@ -506,10 +515,10 @@ bool Parse0514(ots::OpenTypeFile *file,
subtable.set_offset(records[i].non_default_offset);
uint32_t num_mappings = 0;
if (!subtable.ReadU32(&num_mappings)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read number of mappings in variation selector record %d", i);
}
if (!num_mappings || num_mappings > kMaxCMAPGroups) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Number of mappings too high (%d) in variation selector record %d", num_mappings, i);
}
uint32_t last_unicode_value = 0;
@ -520,14 +529,14 @@ bool Parse0514(ots::OpenTypeFile *file,
for (unsigned j = 0; j < num_mappings; ++j) {
if (!subtable.ReadU24(&mappings[j].unicode_value) ||
!subtable.ReadU16(&mappings[j].glyph_id)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read mapping %d in variation selector record %d", j, i);
}
if (mappings[j].glyph_id == 0 ||
mappings[j].unicode_value == 0 ||
mappings[j].unicode_value > kUnicodeUpperLimit ||
(last_unicode_value &&
mappings[j].unicode_value <= last_unicode_value)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad mapping (%04X -> %d) in mapping %d of variation selector %d", mappings[j].unicode_value, mappings[j].glyph_id, j, i);
}
last_unicode_value = mappings[j].unicode_value;
}
@ -535,7 +544,7 @@ bool Parse0514(ots::OpenTypeFile *file,
}
if (subtable.offset() != length) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad subtable offset (%ld != %ld)", subtable.offset(), length);
}
file->cmap->subtable_0_5_14_length = subtable.offset();
return true;
@ -546,11 +555,11 @@ bool Parse100(ots::OpenTypeFile *file, const uint8_t *data, size_t length) {
ots::Buffer subtable(data, length);
if (!subtable.Skip(4)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad cmap subtable");
}
uint16_t language = 0;
if (!subtable.ReadU16(&language)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read language in cmap subtable");
}
if (language) {
// simsun.ttf has non-zero language id.
@ -561,7 +570,7 @@ bool Parse100(ots::OpenTypeFile *file, const uint8_t *data, size_t length) {
for (size_t i = 0; i < kFormat0ArraySize; ++i) {
uint8_t glyph_id = 0;
if (!subtable.ReadU8(&glyph_id)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read glyph id at array[%ld] in cmap subtable", i);
}
file->cmap->subtable_1_0_0.push_back(glyph_id);
}
@ -581,14 +590,14 @@ bool ots_cmap_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
uint16_t num_tables = 0;
if (!table.ReadU16(&version) ||
!table.ReadU16(&num_tables)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read structure of cmap");
}
if (version != 0) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Non zero cmap version (%d)", version);
}
if (!num_tables) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("No subtables in cmap!");
}
std::vector<CMAPSubtableHeader> subtable_headers;
@ -601,7 +610,7 @@ bool ots_cmap_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
if (!table.ReadU16(&subt.platform) ||
!table.ReadU16(&subt.encoding) ||
!table.ReadU32(&subt.offset)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read subtable information cmap subtable %d", i);
}
subtable_headers.push_back(subt);
@ -610,23 +619,14 @@ bool ots_cmap_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
const size_t data_offset = table.offset();
// make sure that all the offsets are valid.
uint32_t last_id = 0;
for (unsigned i = 0; i < num_tables; ++i) {
if (subtable_headers[i].offset > 1024 * 1024 * 1024) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad subtable offset in cmap subtable %d", i);
}
if (subtable_headers[i].offset < data_offset ||
subtable_headers[i].offset >= length) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad subtable offset (%d) in cmap subtable %d", subtable_headers[i].offset, i);
}
// check if the table is sorted first by platform ID, then by encoding ID.
uint32_t current_id
= (subtable_headers[i].platform << 16) + subtable_headers[i].encoding;
if ((i != 0) && (last_id >= current_id)) {
return OTS_FAILURE();
}
last_id = current_id;
}
// the format of the table is the first couple of bytes in the table. The
@ -634,50 +634,77 @@ bool ots_cmap_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
for (unsigned i = 0; i < num_tables; ++i) {
table.set_offset(subtable_headers[i].offset);
if (!table.ReadU16(&subtable_headers[i].format)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read cmap subtable header format %d", i);
}
uint16_t len = 0;
uint16_t lang = 0;
switch (subtable_headers[i].format) {
case 0:
case 4:
if (!table.ReadU16(&len)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read cmap subtable %d length", i);
}
if (!table.ReadU16(&lang)) {
return OTS_FAILURE_MSG("Can't read cmap subtable %d language", i);
}
subtable_headers[i].length = len;
subtable_headers[i].language = lang;
break;
case 12:
case 13:
if (!table.Skip(2)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad cmap subtable %d structure", i);
}
if (!table.ReadU32(&subtable_headers[i].length)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can read cmap subtable %d length", i);
}
if (!table.ReadU32(&subtable_headers[i].language)) {
return OTS_FAILURE_MSG("Can't read cmap subtable %d language", i);
}
break;
case 14:
if (!table.ReadU32(&subtable_headers[i].length)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read cmap subtable %d length", i);
}
subtable_headers[i].language = 0;
break;
default:
subtable_headers[i].length = 0;
subtable_headers[i].language = 0;
break;
}
}
// check if the table is sorted first by platform ID, then by encoding ID.
uint32_t last_id = 0;
for (unsigned i = 0; i < num_tables; ++i) {
uint32_t current_id
= (subtable_headers[i].platform << 24)
+ (subtable_headers[i].encoding << 16)
+ subtable_headers[i].language;
if ((i != 0) && (last_id >= current_id)) {
return OTS_FAILURE_MSG("subtable %d with platform ID %d, encoding ID %d, language ID %d "
"following subtable with platform ID %d, encoding ID %d, language ID %d",
i,
(uint8_t)(current_id >> 24), (uint8_t)(current_id >> 16), (uint8_t)(current_id),
(uint8_t)(last_id >> 24), (uint8_t)(last_id >> 16), (uint8_t)(last_id));
}
last_id = current_id;
}
// Now, verify that all the lengths are sane
for (unsigned i = 0; i < num_tables; ++i) {
if (!subtable_headers[i].length) continue;
if (subtable_headers[i].length > 1024 * 1024 * 1024) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad cmap subtable %d length", i);
}
// We know that both the offset and length are < 1GB, so the following
// addition doesn't overflow
const uint32_t end_byte
= subtable_headers[i].offset + subtable_headers[i].length;
if (end_byte > length) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Over long cmap subtable %d @ %d for %d", i, subtable_headers[i].offset, subtable_headers[i].length);
}
}
@ -705,14 +732,14 @@ bool ots_cmap_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
for (unsigned i = 0; i < overlap_checker.size(); ++i) {
overlap_count += (overlap_checker[i].second ? 1 : -1);
if (overlap_count > 1) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Excessive overlap count %d", overlap_count);
}
}
// we grab the number of glyphs in the file from the maxp table to make sure
// that the character map isn't referencing anything beyound this range.
if (!file->maxp) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("No maxp table in font! Needed by cmap.");
}
const uint16_t num_glyphs = file->maxp->num_glyphs;
@ -752,27 +779,27 @@ bool ots_cmap_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
// recovered in ots_cmap_serialise().
if (!ParseFormat4(file, 3, 1, data + subtable_headers[i].offset,
subtable_headers[i].length, num_glyphs)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse format 4 cmap subtable %d", i);
}
} else if ((subtable_headers[i].encoding == 3) &&
(subtable_headers[i].format == 4)) {
// parse and output the 0-3-4 table as 0-3-4 table.
if (!ParseFormat4(file, 0, 3, data + subtable_headers[i].offset,
subtable_headers[i].length, num_glyphs)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse format 4 cmap subtable %d", i);
}
} else if ((subtable_headers[i].encoding == 3) &&
(subtable_headers[i].format == 12)) {
// parse and output the 0-3-12 table as 3-10-12 table.
if (!Parse31012(file, data + subtable_headers[i].offset,
subtable_headers[i].length, num_glyphs)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse format 12 cmap subtable %d", i);
}
} else if ((subtable_headers[i].encoding == 5) &&
(subtable_headers[i].format == 14)) {
if (!Parse0514(file, data + subtable_headers[i].offset,
subtable_headers[i].length, num_glyphs)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse format 14 cmap subtable %d", i);
}
}
} else if (subtable_headers[i].platform == 1) {

View File

@ -5,7 +5,9 @@
#include "cvt.h"
// cvt - Control Value Table
// http://www.microsoft.com/opentype/otspec/cvt.htm
// http://www.microsoft.com/typography/otspec/cvt.htm
#define TABLE_NAME "cvt"
namespace ots {
@ -16,15 +18,15 @@ bool ots_cvt_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
file->cvt = cvt;
if (length >= 128 * 1024u) {
return OTS_FAILURE(); // almost all cvt tables are less than 4k bytes.
return OTS_FAILURE_MSG("Length (%d) > 120K"); // almost all cvt tables are less than 4k bytes.
}
if (length % 2 != 0) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Uneven cvt length (%d)", length);
}
if (!table.Skip(length)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Length too high");
}
cvt->data = data;
@ -43,7 +45,7 @@ bool ots_cvt_serialise(OTSStream *out, OpenTypeFile *file) {
const OpenTypeCVT *cvt = file->cvt;
if (!out->Write(cvt->data, cvt->length)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write CVT table");
}
return true;

View File

@ -5,7 +5,9 @@
#include "fpgm.h"
// fpgm - Font Program
// http://www.microsoft.com/opentype/otspec/fpgm.htm
// http://www.microsoft.com/typography/otspec/fpgm.htm
#define TABLE_NAME "fpgm"
namespace ots {
@ -16,11 +18,11 @@ bool ots_fpgm_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
file->fpgm = fpgm;
if (length >= 128 * 1024u) {
return OTS_FAILURE(); // almost all fpgm tables are less than 5k bytes.
return OTS_FAILURE_MSG("length (%ld) > 120", length); // almost all fpgm tables are less than 5k bytes.
}
if (!table.Skip(length)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad fpgm length");
}
fpgm->data = data;
@ -37,7 +39,7 @@ bool ots_fpgm_serialise(OTSStream *out, OpenTypeFile *file) {
const OpenTypeFPGM *fpgm = file->fpgm;
if (!out->Write(fpgm->data, fpgm->length)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write fpgm");
}
return true;

View File

@ -5,10 +5,16 @@
#include "gasp.h"
// gasp - Grid-fitting And Scan-conversion Procedure
// http://www.microsoft.com/opentype/otspec/gasp.htm
// http://www.microsoft.com/typography/otspec/gasp.htm
#define TABLE_NAME "gasp"
#define DROP_THIS_TABLE \
do { delete file->gasp; file->gasp = 0; } while (0)
do { \
delete file->gasp; \
file->gasp = 0; \
OTS_FAILURE_MSG("Table discarded"); \
} while (0)
namespace ots {
@ -21,7 +27,7 @@ bool ots_gasp_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
uint16_t num_ranges = 0;
if (!table.ReadU16(&gasp->version) ||
!table.ReadU16(&num_ranges)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read table header");
}
if (gasp->version > 1) {
@ -43,7 +49,7 @@ bool ots_gasp_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
uint16_t behavior = 0;
if (!table.ReadU16(&max_ppem) ||
!table.ReadU16(&behavior)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read subrange %d", i);
}
if ((i > 0) && (gasp->gasp_ranges[i - 1].first >= max_ppem)) {
// The records in the gaspRange[] array must be sorted in order of
@ -86,13 +92,13 @@ bool ots_gasp_serialise(OTSStream *out, OpenTypeFile *file) {
if (!out->WriteU16(gasp->version) ||
!out->WriteU16(gasp->gasp_ranges.size())) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("failed to write gasp header");
}
for (unsigned i = 0; i < gasp->gasp_ranges.size(); ++i) {
if (!out->WriteU16(gasp->gasp_ranges[i].first) ||
!out->WriteU16(gasp->gasp_ranges[i].second)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write gasp subtable %d", i);
}
}

View File

@ -6,7 +6,7 @@
#define OTS_GASP_H_
#include <new>
#include <utility> // std::pair
#include <utility>
#include <vector>
#include "ots.h"

View File

@ -30,7 +30,7 @@ const uint16_t kMaxCaretValueFormat = 2;
bool ParseGlyphClassDefTable(ots::OpenTypeFile *file, const uint8_t *data,
size_t length, const uint16_t num_glyphs) {
return ots::ParseClassDefTable(data, length, num_glyphs,
return ots::ParseClassDefTable(file, data, length, num_glyphs,
kMaxGlyphClassDefValue);
}
@ -42,38 +42,37 @@ bool ParseAttachListTable(ots::OpenTypeFile *file, const uint8_t *data,
uint16_t glyph_count = 0;
if (!subtable.ReadU16(&offset_coverage) ||
!subtable.ReadU16(&glyph_count)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read gdef header");
}
const unsigned attach_points_end =
2 * static_cast<unsigned>(glyph_count) + 4;
if (attach_points_end > std::numeric_limits<uint16_t>::max()) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad glyph count in gdef");
}
if (offset_coverage == 0 || offset_coverage >= length ||
offset_coverage < attach_points_end) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad coverage offset %d", offset_coverage);
}
if (glyph_count > num_glyphs) {
OTS_WARNING("bad glyph count: %u", glyph_count);
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad glyph count %u", glyph_count);
}
std::vector<uint16_t> attach_points;
attach_points.resize(glyph_count);
for (unsigned i = 0; i < glyph_count; ++i) {
if (!subtable.ReadU16(&attach_points[i])) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read attachment point %d", i);
}
if (attach_points[i] >= length ||
attach_points[i] < attach_points_end) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad attachment point %d of %d", i, attach_points[i]);
}
}
// Parse coverage table
if (!ots::ParseCoverageTable(data + offset_coverage,
if (!ots::ParseCoverageTable(file, data + offset_coverage,
length - offset_coverage, num_glyphs)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad coverage table");
}
// Parse attach point table
@ -81,22 +80,21 @@ bool ParseAttachListTable(ots::OpenTypeFile *file, const uint8_t *data,
subtable.set_offset(attach_points[i]);
uint16_t point_count = 0;
if (!subtable.ReadU16(&point_count)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read point count %d", i);
}
if (point_count == 0) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("zero point count %d", i);
}
uint16_t last_point_index = 0;
uint16_t point_index = 0;
for (unsigned j = 0; j < point_count; ++j) {
if (!subtable.ReadU16(&point_index)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read point index %d in point %d", j, i);
}
// Contour point indeces are in increasing numerical order
if (last_point_index != 0 && last_point_index >= point_index) {
OTS_WARNING("bad contour indeces: %u >= %u",
return OTS_FAILURE_MSG("bad contour indeces: %u >= %u",
last_point_index, point_index);
return OTS_FAILURE();
}
last_point_index = point_index;
}
@ -111,37 +109,36 @@ bool ParseLigCaretListTable(ots::OpenTypeFile *file, const uint8_t *data,
uint16_t lig_glyph_count = 0;
if (!subtable.ReadU16(&offset_coverage) ||
!subtable.ReadU16(&lig_glyph_count)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read caret structure");
}
const unsigned lig_glyphs_end =
2 * static_cast<unsigned>(lig_glyph_count) + 4;
if (lig_glyphs_end > std::numeric_limits<uint16_t>::max()) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad caret structure");
}
if (offset_coverage == 0 || offset_coverage >= length ||
offset_coverage < lig_glyphs_end) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad caret coverate offset %d", offset_coverage);
}
if (lig_glyph_count > num_glyphs) {
OTS_WARNING("bad ligature glyph count: %u", lig_glyph_count);
return OTS_FAILURE();
return OTS_FAILURE_MSG("bad ligature glyph count: %u", lig_glyph_count);
}
std::vector<uint16_t> lig_glyphs;
lig_glyphs.resize(lig_glyph_count);
for (unsigned i = 0; i < lig_glyph_count; ++i) {
if (!subtable.ReadU16(&lig_glyphs[i])) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read ligature glyph location %d", i);
}
if (lig_glyphs[i] >= length || lig_glyphs[i] < lig_glyphs_end) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad ligature glyph location %d in glyph %d", lig_glyphs[i], i);
}
}
// Parse coverage table
if (!ots::ParseCoverageTable(data + offset_coverage,
if (!ots::ParseCoverageTable(file, data + offset_coverage,
length - offset_coverage, num_glyphs)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't parse caret coverage table");
}
// Parse ligature glyph table
@ -149,51 +146,41 @@ bool ParseLigCaretListTable(ots::OpenTypeFile *file, const uint8_t *data,
subtable.set_offset(lig_glyphs[i]);
uint16_t caret_count = 0;
if (!subtable.ReadU16(&caret_count)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read caret count for glyph %d", i);
}
if (caret_count == 0) {
OTS_WARNING("bad caret value count: %u", caret_count);
return OTS_FAILURE();
return OTS_FAILURE_MSG("bad caret value count: %u", caret_count);
}
std::vector<uint16_t> caret_values;
caret_values.resize(caret_count);
uint16_t last_offset_caret = 0;
unsigned caret_values_end = 2 * static_cast<unsigned>(caret_count) + 2;
std::vector<uint16_t> caret_value_offsets;
caret_value_offsets.resize(caret_count);
unsigned caret_value_offsets_end = 2 * static_cast<unsigned>(caret_count) + 2;
for (unsigned j = 0; j < caret_count; ++j) {
if (!subtable.ReadU16(&caret_values[j])) {
return OTS_FAILURE();
if (!subtable.ReadU16(&caret_value_offsets[j])) {
return OTS_FAILURE_MSG("Can't read caret offset %d for glyph %d", j, i);
}
if (caret_values[j] >= length || caret_values[j] < caret_values_end) {
return OTS_FAILURE();
if (caret_value_offsets[j] >= length || caret_value_offsets[j] < caret_value_offsets_end) {
return OTS_FAILURE_MSG("Bad caret offset %d for caret %d glyph %d", caret_value_offsets[j], j, i);
}
// Caret offsets are in increasing coordinate order
if (last_offset_caret != 0 && last_offset_caret >= caret_values[j]) {
OTS_WARNING("offset isn't in increasing coordinate order: %u >= %u",
last_offset_caret, caret_values[j]);
return OTS_FAILURE();
}
last_offset_caret = caret_values[j];
}
// Parse caret values table
for (unsigned j = 0; j < caret_count; ++j) {
subtable.set_offset(lig_glyphs[i] + caret_values[j]);
subtable.set_offset(lig_glyphs[i] + caret_value_offsets[j]);
uint16_t caret_format = 0;
if (!subtable.ReadU16(&caret_format)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read caret values table %d in glyph %d", j, i);
}
// TODO(bashi): We only support caret value format 1 and 2 for now
// because there are no fonts which contain caret value format 3
// as far as we investigated.
if (caret_format == 0 || caret_format > kMaxCaretValueFormat) {
OTS_WARNING("bad caret value format: %u", caret_format);
return OTS_FAILURE();
return OTS_FAILURE_MSG("bad caret value format: %u", caret_format);
}
// CaretValueFormats contain a 2-byte field which could be
// arbitrary value.
if (!subtable.Skip(2)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad caret value table structure %d in glyph %d", j, i);
}
}
}
@ -202,7 +189,7 @@ bool ParseLigCaretListTable(ots::OpenTypeFile *file, const uint8_t *data,
bool ParseMarkAttachClassDefTable(ots::OpenTypeFile *file, const uint8_t *data,
size_t length, const uint16_t num_glyphs) {
return ots::ParseClassDefTable(data, length, num_glyphs, kMaxClassDefValue);
return ots::ParseClassDefTable(file, data, length, num_glyphs, kMaxClassDefValue);
}
bool ParseMarkGlyphSetsDefTable(ots::OpenTypeFile *file, const uint8_t *data,
@ -212,29 +199,28 @@ bool ParseMarkGlyphSetsDefTable(ots::OpenTypeFile *file, const uint8_t *data,
uint16_t mark_set_count = 0;
if (!subtable.ReadU16(&format) ||
!subtable.ReadU16(&mark_set_count)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can' read mark glyph table structure");
}
if (format != 1) {
OTS_WARNING("bad mark glyph set table format: %u", format);
return OTS_FAILURE();
return OTS_FAILURE_MSG("bad mark glyph set table format: %u", format);
}
const unsigned mark_sets_end = 2 * static_cast<unsigned>(mark_set_count) + 4;
if (mark_sets_end > std::numeric_limits<uint16_t>::max()) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad mark_set %d", mark_sets_end);
}
for (unsigned i = 0; i < mark_set_count; ++i) {
uint32_t offset_coverage = 0;
if (!subtable.ReadU32(&offset_coverage)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read covrage location for mark set %d", i);
}
if (offset_coverage >= length ||
offset_coverage < mark_sets_end) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad coverage location %d for mark set %d", offset_coverage, i);
}
if (!ots::ParseCoverageTable(data + offset_coverage,
if (!ots::ParseCoverageTable(file, data + offset_coverage,
length - offset_coverage, num_glyphs)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse coverage table for mark set %d", i);
}
}
file->gdef->num_mark_glyph_sets = mark_set_count;
@ -243,11 +229,11 @@ bool ParseMarkGlyphSetsDefTable(ots::OpenTypeFile *file, const uint8_t *data,
} // namespace
#define DROP_THIS_TABLE \
#define DROP_THIS_TABLE(msg_) \
do { \
file->gdef->data = 0; \
file->gdef->length = 0; \
OTS_FAILURE_MSG("OpenType layout data discarded"); \
OTS_FAILURE_MSG(msg_ ", table discarded"); \
} while (0)
namespace ots {
@ -256,7 +242,7 @@ bool ots_gdef_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
// Grab the number of glyphs in the file from the maxp table to check
// GlyphIDs in GDEF table.
if (!file->maxp) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("No maxp table in font, needed by GDEF");
}
const uint16_t num_glyphs = file->maxp->num_glyphs;
@ -267,13 +253,11 @@ bool ots_gdef_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
uint32_t version = 0;
if (!table.ReadU32(&version)) {
OTS_WARNING("incomplete GDEF table");
DROP_THIS_TABLE;
DROP_THIS_TABLE("Incomplete table");
return true;
}
if (version < 0x00010000 || version == 0x00010001) {
OTS_WARNING("bad GDEF version");
DROP_THIS_TABLE;
DROP_THIS_TABLE("Bad version");
return true;
}
@ -289,20 +273,18 @@ bool ots_gdef_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
!table.ReadU16(&offset_attach_list) ||
!table.ReadU16(&offset_lig_caret_list) ||
!table.ReadU16(&offset_mark_attach_class_def)) {
OTS_WARNING("incomplete GDEF table");
DROP_THIS_TABLE;
DROP_THIS_TABLE("Incomplete table");
return true;
}
uint16_t offset_mark_glyph_sets_def = 0;
if (gdef->version_2) {
if (!table.ReadU16(&offset_mark_glyph_sets_def)) {
OTS_WARNING("incomplete GDEF table");
DROP_THIS_TABLE;
DROP_THIS_TABLE("Incomplete table");
return true;
}
}
unsigned gdef_header_end = 8;
unsigned gdef_header_end = 4 + 4 * 2;
if (gdef->version_2)
gdef_header_end += 2;
@ -310,15 +292,13 @@ bool ots_gdef_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
if (offset_glyph_class_def) {
if (offset_glyph_class_def >= length ||
offset_glyph_class_def < gdef_header_end) {
OTS_WARNING("invalid offset to glyph classes");
DROP_THIS_TABLE;
DROP_THIS_TABLE("Invalid offset to glyph classes");
return true;
}
if (!ParseGlyphClassDefTable(file, data + offset_glyph_class_def,
length - offset_glyph_class_def,
num_glyphs)) {
OTS_WARNING("invalid glyph classes");
DROP_THIS_TABLE;
DROP_THIS_TABLE("Invalid glyph classes");
return true;
}
gdef->has_glyph_class_def = true;
@ -327,15 +307,13 @@ bool ots_gdef_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
if (offset_attach_list) {
if (offset_attach_list >= length ||
offset_attach_list < gdef_header_end) {
OTS_WARNING("invalid offset to attachment list");
DROP_THIS_TABLE;
DROP_THIS_TABLE("Invalid offset to attachment list");
return true;
}
if (!ParseAttachListTable(file, data + offset_attach_list,
length - offset_attach_list,
num_glyphs)) {
OTS_WARNING("invalid attachment list");
DROP_THIS_TABLE;
DROP_THIS_TABLE("Invalid attachment list");
return true;
}
}
@ -343,15 +321,13 @@ bool ots_gdef_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
if (offset_lig_caret_list) {
if (offset_lig_caret_list >= length ||
offset_lig_caret_list < gdef_header_end) {
OTS_WARNING("invalid offset to lig-caret list");
DROP_THIS_TABLE;
DROP_THIS_TABLE("Invalid offset to ligature caret list");
return true;
}
if (!ParseLigCaretListTable(file, data + offset_lig_caret_list,
length - offset_lig_caret_list,
num_glyphs)) {
OTS_WARNING("invalid ligature caret list");
DROP_THIS_TABLE;
DROP_THIS_TABLE("Invalid ligature caret list");
return true;
}
}
@ -359,15 +335,13 @@ bool ots_gdef_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
if (offset_mark_attach_class_def) {
if (offset_mark_attach_class_def >= length ||
offset_mark_attach_class_def < gdef_header_end) {
OTS_WARNING("invalid offset to mark attachment list");
return OTS_FAILURE();
return OTS_FAILURE_MSG("Invalid offset to mark attachment list");
}
if (!ParseMarkAttachClassDefTable(file,
data + offset_mark_attach_class_def,
length - offset_mark_attach_class_def,
num_glyphs)) {
OTS_WARNING("invalid mark attachment list");
DROP_THIS_TABLE;
DROP_THIS_TABLE("Invalid mark attachment list");
return true;
}
gdef->has_mark_attachment_class_def = true;
@ -376,15 +350,13 @@ bool ots_gdef_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
if (offset_mark_glyph_sets_def) {
if (offset_mark_glyph_sets_def >= length ||
offset_mark_glyph_sets_def < gdef_header_end) {
OTS_WARNING("invalid offset to mark glyph sets");
return OTS_FAILURE();
return OTS_FAILURE_MSG("invalid offset to mark glyph sets");
}
if (!ParseMarkGlyphSetsDefTable(file,
data + offset_mark_glyph_sets_def,
length - offset_mark_glyph_sets_def,
num_glyphs)) {
OTS_WARNING("invalid mark glyph sets");
DROP_THIS_TABLE;
DROP_THIS_TABLE("Invalid mark glyph sets");
return true;
}
gdef->has_mark_glyph_sets_def = true;
@ -395,16 +367,12 @@ bool ots_gdef_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
}
bool ots_gdef_should_serialise(OpenTypeFile *file) {
const bool needed_tables_dropped =
(file->gsub && file->gsub->data == NULL) ||
(file->gpos && file->gpos->data == NULL);
return file->gdef != NULL && file->gdef->data != NULL &&
!needed_tables_dropped;
return file->gdef != NULL && file->gdef->data != NULL;
}
bool ots_gdef_serialise(OTSStream *out, OpenTypeFile *file) {
if (!out->Write(file->gdef->data, file->gdef->length)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write GDEF table");
}
return true;

View File

@ -12,11 +12,14 @@
#include "maxp.h"
// glyf - Glyph Data
// http://www.microsoft.com/opentype/otspec/glyf.htm
// http://www.microsoft.com/typography/otspec/glyf.htm
#define TABLE_NAME "glyf"
namespace {
bool ParseFlagsForSimpleGlyph(ots::Buffer *table,
bool ParseFlagsForSimpleGlyph(ots::OpenTypeFile *file,
ots::Buffer *table,
uint32_t gly_length,
uint32_t num_flags,
uint32_t *flags_count_logical,
@ -24,7 +27,7 @@ bool ParseFlagsForSimpleGlyph(ots::Buffer *table,
uint32_t *xy_coordinates_length) {
uint8_t flag = 0;
if (!table->ReadU8(&flag)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read flag");
}
uint32_t delta = 0;
@ -42,31 +45,31 @@ bool ParseFlagsForSimpleGlyph(ots::Buffer *table,
if (flag & (1u << 3)) { // repeat
if (*flags_count_logical + 1 >= num_flags) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Count too high (%d + 1 >= %d)", *flags_count_logical, num_flags);
}
uint8_t repeat = 0;
if (!table->ReadU8(&repeat)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read repeat value");
}
if (repeat == 0) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Zero repeat");
}
delta += (delta * repeat);
*flags_count_logical += repeat;
if (*flags_count_logical >= num_flags) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Count too high (%d >= %d)", *flags_count_logical, num_flags);
}
++(*flags_count_physical);
}
if ((flag & (1u << 6)) || (flag & (1u << 7))) { // reserved flags
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad flag value (%d)", flag);
}
*xy_coordinates_length += delta;
if (gly_length < *xy_coordinates_length) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Glyph coordinates length too low (%d < %d)", gly_length, *xy_coordinates_length);
}
return true;
@ -83,30 +86,30 @@ bool ParseSimpleGlyph(ots::OpenTypeFile *file, const uint8_t *data,
for (int i = 0; i < num_contours; ++i) {
uint16_t tmp_index = 0;
if (!table->ReadU16(&tmp_index)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read contour index %d", i);
}
if (tmp_index == 0xffffu) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad contour index %d", i);
}
// check if the indices are monotonically increasing
if (i && (tmp_index + 1 <= num_flags)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Decreasing contour index %d + 1 <= %d", tmp_index, num_flags);
}
num_flags = tmp_index + 1;
}
uint16_t bytecode_length = 0;
if (!table->ReadU16(&bytecode_length)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read bytecode length");
}
if ((file->maxp->version_1) &&
(file->maxp->max_size_glyf_instructions < bytecode_length)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bytecode length too high %d", bytecode_length);
}
const uint32_t gly_header_length = 10 + num_contours * 2 + 2;
if (gly_length < (gly_header_length + bytecode_length)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Glyph header length too high %d", gly_header_length);
}
if (ots::g_transcode_hints) {
@ -124,7 +127,7 @@ bool ParseSimpleGlyph(ots::OpenTypeFile *file, const uint8_t *data,
}
if (!table->Skip(bytecode_length)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't skip bytecode of length %d", bytecode_length);
}
uint32_t flags_count_physical = 0; // on memory
@ -132,26 +135,27 @@ bool ParseSimpleGlyph(ots::OpenTypeFile *file, const uint8_t *data,
for (uint32_t flags_count_logical = 0;
flags_count_logical < num_flags;
++flags_count_logical, ++flags_count_physical) {
if (!ParseFlagsForSimpleGlyph(table,
if (!ParseFlagsForSimpleGlyph(file,
table,
gly_length,
num_flags,
&flags_count_logical,
&flags_count_physical,
&xy_coordinates_length)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse glyph flags %d", flags_count_logical);
}
}
if (gly_length < (gly_header_length + bytecode_length +
flags_count_physical + xy_coordinates_length)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Glyph too short %d", gly_length);
}
if (gly_length - (gly_header_length + bytecode_length +
flags_count_physical + xy_coordinates_length) > 3) {
// We allow 0-3 bytes difference since gly_length is 4-bytes aligned,
// zero-padded length.
return OTS_FAILURE();
return OTS_FAILURE_MSG("Invalid glyph length %d", gly_length);
}
glyf->iov.push_back(std::make_pair(
@ -175,7 +179,7 @@ bool ots_glyf_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
Buffer table(data, length);
if (!file->maxp || !file->loca || !file->head) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Missing maxp or loca or head table needed by glyf table");
}
OpenTypeGLYF *glyf = new OpenTypeGLYF;
@ -185,7 +189,7 @@ bool ots_glyf_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
std::vector<uint32_t> &offsets = file->loca->offsets;
if (offsets.size() != num_glyphs + 1) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Invalide glyph offsets size %ld != %d", offsets.size(), num_glyphs + 1);
}
std::vector<uint32_t> resulting_offsets(num_glyphs + 1);
@ -202,15 +206,15 @@ bool ots_glyf_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
}
if (gly_offset >= length) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Glyph %d offset %d too high %ld", i, gly_offset, length);
}
// Since these are unsigned types, the compiler is not allowed to assume
// that they never overflow.
if (gly_offset + gly_length < gly_offset) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Glyph %d length (%d < 0)!", i, gly_length);
}
if (gly_offset + gly_length > length) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Glyph %d length %d too high", i, gly_length);
}
table.set_offset(gly_offset);
@ -220,12 +224,12 @@ bool ots_glyf_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
!table.ReadS16(&ymin) ||
!table.ReadS16(&xmax) ||
!table.ReadS16(&ymax)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read glyph %d header", i);
}
if (num_contours <= -2) {
// -2, -3, -4, ... are reserved for future use.
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad number of contours %d in glyph %d", num_contours, i);
}
// workaround for fonts in http://www.princexml.com/fonts/
@ -238,7 +242,7 @@ bool ots_glyf_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
}
if (xmin > xmax || ymin > ymax) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad bounding box values bl=(%d, %d), tr=(%d, %d) in glyph %d", xmin, ymin, xmax, ymax, i);
}
unsigned new_size = 0;
@ -246,7 +250,7 @@ bool ots_glyf_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
// this is a simple glyph and might contain bytecode
if (!ParseSimpleGlyph(file, data, &table,
num_contours, gly_offset, gly_length, &new_size)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse glyph %d", i);
}
} else {
// it's a composite glyph without any bytecode. Enqueue the whole thing
@ -291,7 +295,7 @@ bool ots_glyf_serialise(OTSStream *out, OpenTypeFile *file) {
for (unsigned i = 0; i < glyf->iov.size(); ++i) {
if (!out->Write(glyf->iov[i].first, glyf->iov[i].second)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Falied to write glyph %d", i);
}
}

View File

@ -6,7 +6,7 @@
#define OTS_GLYF_H_
#include <new>
#include <utility> // std::pair
#include <utility>
#include <vector>
#include "ots.h"

View File

@ -7,8 +7,6 @@
#include <limits>
#include <vector>
#include "gdef.h"
#include "gsub.h"
#include "layout.h"
#include "maxp.h"
@ -71,22 +69,22 @@ const ots::LookupSubtableParser::TypeParser kGposTypeParsers[] = {
{GPOS_TYPE_EXTENSION_POSITIONING, ParseExtensionPositioning}
};
// TODO(bashi): Port Chromium's arraysize macro and use it instead of sizeof().
const ots::LookupSubtableParser kGposLookupSubtableParser = {
sizeof(kGposTypeParsers) / sizeof(kGposTypeParsers[0]),
arraysize(kGposTypeParsers),
GPOS_TYPE_EXTENSION_POSITIONING, kGposTypeParsers
};
// Shared Tables: ValueRecord, Anchor Table, and MarkArray
bool ParseValueRecord(ots::Buffer* subtable, const uint8_t *data,
bool ParseValueRecord(const ots::OpenTypeFile *file,
ots::Buffer* subtable, const uint8_t *data,
const size_t length, const uint16_t value_format) {
// Check existence of adjustment fields.
for (unsigned i = 0; i < 4; ++i) {
if ((value_format >> i) & 0x1) {
// Just read the field since these fileds could take an arbitrary values.
if (!subtable->Skip(2)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read value reacord component");
}
}
}
@ -96,16 +94,16 @@ bool ParseValueRecord(ots::Buffer* subtable, const uint8_t *data,
if ((value_format >> (i + 4)) & 0x1) {
uint16_t offset = 0;
if (!subtable->ReadU16(&offset)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read value record offset");
}
if (offset) {
// TODO(bashi): Is it possible that device tables locate before
// this record? No fonts contain such offset AKAIF.
if (offset >= length) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Value record offset too high %d >= %ld", offset, length);
}
if (!ots::ParseDeviceTable(data + offset, length - offset)) {
return OTS_FAILURE();
if (!ots::ParseDeviceTable(file, data + offset, length - offset)) {
return OTS_FAILURE_MSG("Failed to parse device table in value record");
}
}
}
@ -113,18 +111,19 @@ bool ParseValueRecord(ots::Buffer* subtable, const uint8_t *data,
return true;
}
bool ParseAnchorTable(const uint8_t *data, const size_t length) {
bool ParseAnchorTable(const ots::OpenTypeFile *file,
const uint8_t *data, const size_t length) {
ots::Buffer subtable(data, length);
uint16_t format = 0;
// Read format and skip 2 2-byte fields that could be arbitrary values.
if (!subtable.ReadU16(&format) ||
!subtable.Skip(4)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Faled to read anchor table");
}
if (format == 0 || format > kMaxAnchorFormat) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad Anchor table format %d", format);
}
// Format 2 and 3 has additional fields.
@ -133,68 +132,69 @@ bool ParseAnchorTable(const uint8_t *data, const size_t length) {
// arbitrary value.
uint16_t anchor_point = 0;
if (!subtable.ReadU16(&anchor_point)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read anchor point in format 2 Anchor Table");
}
} else if (format == 3) {
uint16_t offset_x_device = 0;
uint16_t offset_y_device = 0;
if (!subtable.ReadU16(&offset_x_device) ||
!subtable.ReadU16(&offset_y_device)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read device table offsets in format 3 anchor table");
}
const unsigned format_end = static_cast<unsigned>(10);
if (offset_x_device) {
if (offset_x_device < format_end || offset_x_device >= length) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad x device table offset %d", offset_x_device);
}
if (!ots::ParseDeviceTable(data + offset_x_device,
if (!ots::ParseDeviceTable(file, data + offset_x_device,
length - offset_x_device)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse device table in anchor table");
}
}
if (offset_y_device) {
if (offset_y_device < format_end || offset_y_device >= length) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad y device table offset %d", offset_y_device);
}
if (!ots::ParseDeviceTable(data + offset_y_device,
if (!ots::ParseDeviceTable(file, data + offset_y_device,
length - offset_y_device)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse device table in anchor table");
}
}
}
return true;
}
bool ParseMarkArrayTable(const uint8_t *data, const size_t length,
bool ParseMarkArrayTable(const ots::OpenTypeFile *file,
const uint8_t *data, const size_t length,
const uint16_t class_count) {
ots::Buffer subtable(data, length);
uint16_t mark_count = 0;
if (!subtable.ReadU16(&mark_count)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read mark table length");
}
// MarkRecord consists of 4-bytes.
const unsigned mark_records_end = 4 * static_cast<unsigned>(mark_count) + 2;
if (mark_records_end > std::numeric_limits<uint16_t>::max()) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad mark table length");
}
for (unsigned i = 0; i < mark_count; ++i) {
uint16_t class_value = 0;
uint16_t offset_mark_anchor = 0;
if (!subtable.ReadU16(&class_value) ||
!subtable.ReadU16(&offset_mark_anchor)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read mark table %d", i);
}
// |class_value| may take arbitrary values including 0 here so we don't
// check the value.
if (offset_mark_anchor < mark_records_end ||
offset_mark_anchor >= length) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad mark anchor offset %d for mark table %d", offset_mark_anchor, i);
}
if (!ParseAnchorTable(data + offset_mark_anchor,
if (!ParseAnchorTable(file, data + offset_mark_anchor,
length - offset_mark_anchor)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Faled to parse anchor table for mark table %d", i);
}
}
@ -213,42 +213,43 @@ bool ParseSingleAdjustment(const ots::OpenTypeFile *file, const uint8_t *data,
if (!subtable.ReadU16(&format) ||
!subtable.ReadU16(&offset_coverage) ||
!subtable.ReadU16(&value_format)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read single adjustment information");
}
if (format == 1) {
// Format 1 exactly one value record.
if (!ParseValueRecord(&subtable, data, length, value_format)) {
return OTS_FAILURE();
if (!ParseValueRecord(file, &subtable, data, length, value_format)) {
return OTS_FAILURE_MSG("Failed to parse format 1 single adjustment table");
}
} else if (format == 2) {
uint16_t value_count = 0;
if (!subtable.ReadU16(&value_count)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse format 2 single adjustment table");
}
for (unsigned i = 0; i < value_count; ++i) {
if (!ParseValueRecord(&subtable, data, length, value_format)) {
return OTS_FAILURE();
if (!ParseValueRecord(file, &subtable, data, length, value_format)) {
return OTS_FAILURE_MSG("Failed to parse value record %d in format 2 single adjustment table", i);
}
}
} else {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad format %d in single adjustment table", format);
}
if (offset_coverage < subtable.offset() || offset_coverage >= length) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad coverage offset %d in single adjustment table", offset_coverage);
}
if (!ots::ParseCoverageTable(data + offset_coverage,
if (!ots::ParseCoverageTable(file, data + offset_coverage,
length - offset_coverage,
file->maxp->num_glyphs)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse coverage table in single adjustment table");
}
return true;
}
bool ParsePairSetTable(const uint8_t *data, const size_t length,
bool ParsePairSetTable(const ots::OpenTypeFile *file,
const uint8_t *data, const size_t length,
const uint16_t value_format1,
const uint16_t value_format2,
const uint16_t num_glyphs) {
@ -256,28 +257,29 @@ bool ParsePairSetTable(const uint8_t *data, const size_t length,
uint16_t value_count = 0;
if (!subtable.ReadU16(&value_count)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read pair set table structure");
}
for (unsigned i = 0; i < value_count; ++i) {
// Check pair value record.
uint16_t glyph_id = 0;
if (!subtable.ReadU16(&glyph_id)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read glyph in pair value record %d", i);
}
if (glyph_id >= num_glyphs) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("glyph id %d too high >= %d", glyph_id, num_glyphs);
}
if (!ParseValueRecord(&subtable, data, length, value_format1)) {
return OTS_FAILURE();
if (!ParseValueRecord(file, &subtable, data, length, value_format1)) {
return OTS_FAILURE_MSG("Failed to parse value record in format 1 pair set table");
}
if (!ParseValueRecord(&subtable, data, length, value_format2)) {
return OTS_FAILURE();
if (!ParseValueRecord(file, &subtable, data, length, value_format2)) {
return OTS_FAILURE_MSG("Failed to parse value record in format 2 pair set table");
}
}
return true;
}
bool ParsePairPosFormat1(const uint8_t *data, const size_t length,
bool ParsePairPosFormat1(const ots::OpenTypeFile *file,
const uint8_t *data, const size_t length,
const uint16_t value_format1,
const uint16_t value_format2,
const uint16_t num_glyphs) {
@ -285,38 +287,39 @@ bool ParsePairPosFormat1(const uint8_t *data, const size_t length,
// Skip 8 bytes that are already read before.
if (!subtable.Skip(8)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read pair pos table structure");
}
uint16_t pair_set_count = 0;
if (!subtable.ReadU16(&pair_set_count)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read pair pos set count");
}
const unsigned pair_pos_end = 2 * static_cast<unsigned>(pair_set_count) + 10;
if (pair_pos_end > std::numeric_limits<uint16_t>::max()) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad pair set length %d", pair_pos_end);
}
for (unsigned i = 0; i < pair_set_count; ++i) {
uint16_t pair_set_offset = 0;
if (!subtable.ReadU16(&pair_set_offset)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read pair set offset for pair set %d", i);
}
if (pair_set_offset < pair_pos_end || pair_set_offset >= length) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad pair set offset %d for pair set %d", pair_set_offset, i);
}
// Check pair set tables
if (!ParsePairSetTable(data + pair_set_offset, length - pair_set_offset,
if (!ParsePairSetTable(file, data + pair_set_offset, length - pair_set_offset,
value_format1, value_format2,
num_glyphs)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse pair set table %d", i);
}
}
return true;
}
bool ParsePairPosFormat2(const uint8_t *data, const size_t length,
bool ParsePairPosFormat2(const ots::OpenTypeFile *file,
const uint8_t *data, const size_t length,
const uint16_t value_format1,
const uint16_t value_format2,
const uint16_t num_glyphs) {
@ -324,7 +327,7 @@ bool ParsePairPosFormat2(const uint8_t *data, const size_t length,
// Skip 8 bytes that are already read before.
if (!subtable.Skip(8)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read pair pos format 2 structure");
}
uint16_t offset_class_def1 = 0;
@ -335,20 +338,20 @@ bool ParsePairPosFormat2(const uint8_t *data, const size_t length,
!subtable.ReadU16(&offset_class_def2) ||
!subtable.ReadU16(&class1_count) ||
!subtable.ReadU16(&class2_count)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read pair pos format 2 data");
}
// Check class 1 records.
for (unsigned i = 0; i < class1_count; ++i) {
// Check class 2 records.
for (unsigned j = 0; j < class2_count; ++j) {
if (value_format1 && !ParseValueRecord(&subtable, data, length,
if (value_format1 && !ParseValueRecord(file, &subtable, data, length,
value_format1)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse value record 1 %d and %d", j, i);
}
if (value_format2 && !ParseValueRecord(&subtable, data, length,
if (value_format2 && !ParseValueRecord(file, &subtable, data, length,
value_format2)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Falied to parse value record 2 %d and %d", j, i);
}
}
}
@ -356,17 +359,17 @@ bool ParsePairPosFormat2(const uint8_t *data, const size_t length,
// Check class definition tables.
if (offset_class_def1 < subtable.offset() || offset_class_def1 >= length ||
offset_class_def2 < subtable.offset() || offset_class_def2 >= length) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad class definition table offsets %d or %d", offset_class_def1, offset_class_def2);
}
if (!ots::ParseClassDefTable(data + offset_class_def1,
if (!ots::ParseClassDefTable(file, data + offset_class_def1,
length - offset_class_def1,
num_glyphs, kMaxClassDefValue)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse class definition table 1");
}
if (!ots::ParseClassDefTable(data + offset_class_def2,
if (!ots::ParseClassDefTable(file, data + offset_class_def2,
length - offset_class_def2,
num_glyphs, kMaxClassDefValue)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse class definition table 2");
}
return true;
@ -386,30 +389,30 @@ bool ParsePairAdjustment(const ots::OpenTypeFile *file, const uint8_t *data,
!subtable.ReadU16(&offset_coverage) ||
!subtable.ReadU16(&value_format1) ||
!subtable.ReadU16(&value_format2)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read pair adjustment structure");
}
if (format == 1) {
if (!ParsePairPosFormat1(data, length, value_format1, value_format2,
if (!ParsePairPosFormat1(file, data, length, value_format1, value_format2,
file->maxp->num_glyphs)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse pair pos format 1");
}
} else if (format == 2) {
if (!ParsePairPosFormat2(data, length, value_format1, value_format2,
if (!ParsePairPosFormat2(file, data, length, value_format1, value_format2,
file->maxp->num_glyphs)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse pair format 2");
}
} else {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad pos pair format %d", format);
}
if (offset_coverage < subtable.offset() || offset_coverage >= length) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad pair pos offset coverage %d", offset_coverage);
}
if (!ots::ParseCoverageTable(data + offset_coverage,
if (!ots::ParseCoverageTable(file, data + offset_coverage,
length - offset_coverage,
file->maxp->num_glyphs)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse coverage table");
}
return true;
@ -427,89 +430,90 @@ bool ParseCursiveAttachment(const ots::OpenTypeFile *file, const uint8_t *data,
if (!subtable.ReadU16(&format) ||
!subtable.ReadU16(&offset_coverage) ||
!subtable.ReadU16(&entry_exit_count)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read cursive attachment structure");
}
if (format != 1) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad cursive attachment format %d", format);
}
// Check entry exit records.
const unsigned entry_exit_records_end =
2 * static_cast<unsigned>(entry_exit_count) + 6;
if (entry_exit_records_end > std::numeric_limits<uint16_t>::max()) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad entry exit record end %d", entry_exit_records_end);
}
for (unsigned i = 0; i < entry_exit_count; ++i) {
uint16_t offset_entry_anchor = 0;
uint16_t offset_exit_anchor = 0;
if (!subtable.ReadU16(&offset_entry_anchor) ||
!subtable.ReadU16(&offset_exit_anchor)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read entry exit record %d", i);
}
// These offsets could be NULL.
if (offset_entry_anchor) {
if (offset_entry_anchor < entry_exit_records_end ||
offset_entry_anchor >= length) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad entry anchor offset %d in entry exit record %d", offset_entry_anchor, i);
}
if (!ParseAnchorTable(data + offset_entry_anchor,
if (!ParseAnchorTable(file, data + offset_entry_anchor,
length - offset_entry_anchor)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse entry anchor table in entry exit record %d", i);
}
}
if (offset_exit_anchor) {
if (offset_exit_anchor < entry_exit_records_end ||
offset_exit_anchor >= length) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad exit anchor offset %d in entry exit record %d", offset_exit_anchor, i);
}
if (!ParseAnchorTable(data + offset_exit_anchor,
if (!ParseAnchorTable(file, data + offset_exit_anchor,
length - offset_exit_anchor)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse exit anchor table in entry exit record %d", i);
}
}
}
if (offset_coverage < subtable.offset() || offset_coverage >= length) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad coverage offset in cursive attachment %d", offset_coverage);
}
if (!ots::ParseCoverageTable(data + offset_coverage,
if (!ots::ParseCoverageTable(file, data + offset_coverage,
length - offset_coverage,
file->maxp->num_glyphs)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse coverage table in cursive attachment");
}
return true;
}
bool ParseAnchorArrayTable(const uint8_t *data, const size_t length,
bool ParseAnchorArrayTable(const ots::OpenTypeFile *file,
const uint8_t *data, const size_t length,
const uint16_t class_count) {
ots::Buffer subtable(data, length);
uint16_t record_count = 0;
if (!subtable.ReadU16(&record_count)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read anchor array length");
}
const unsigned anchor_array_end = 2 * static_cast<unsigned>(record_count) *
static_cast<unsigned>(class_count) + 2;
if (anchor_array_end > std::numeric_limits<uint16_t>::max()) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad end of anchor array %d", anchor_array_end);
}
for (unsigned i = 0; i < record_count; ++i) {
for (unsigned j = 0; j < class_count; ++j) {
uint16_t offset_record = 0;
if (!subtable.ReadU16(&offset_record)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read anchor array record offset for class %d and record %d", j, i);
}
// |offset_record| could be NULL.
if (offset_record) {
if (offset_record < anchor_array_end || offset_record >= length) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad record offset %d in class %d, record %d", offset_record, j, i);
}
if (!ParseAnchorTable(data + offset_record,
if (!ParseAnchorTable(file, data + offset_record,
length - offset_record)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse anchor table for class %d, record %d", j, i);
}
}
}
@ -517,25 +521,26 @@ bool ParseAnchorArrayTable(const uint8_t *data, const size_t length,
return true;
}
bool ParseLigatureArrayTable(const uint8_t *data, const size_t length,
bool ParseLigatureArrayTable(const ots::OpenTypeFile *file,
const uint8_t *data, const size_t length,
const uint16_t class_count) {
ots::Buffer subtable(data, length);
uint16_t ligature_count = 0;
if (!subtable.ReadU16(&ligature_count)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read ligature count");
}
for (unsigned i = 0; i < ligature_count; ++i) {
uint16_t offset_ligature_attach = 0;
if (!subtable.ReadU16(&offset_ligature_attach)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read ligature offset %d", i);
}
if (offset_ligature_attach < 2 || offset_ligature_attach >= length) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad ligature attachment offset %d in ligature %d", offset_ligature_attach, i);
}
if (!ParseAnchorArrayTable(data + offset_ligature_attach,
if (!ParseAnchorArrayTable(file, data + offset_ligature_attach,
length - offset_ligature_attach, class_count)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse anchor table for ligature %d", i);
}
}
return true;
@ -559,61 +564,61 @@ bool ParseMarkToAttachmentSubtables(const ots::OpenTypeFile *file,
!subtable.ReadU16(&class_count) ||
!subtable.ReadU16(&offset_mark_array) ||
!subtable.ReadU16(&offset_type_specific_array)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read mark attachment subtable header");
}
if (format != 1) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("bad mark attachment subtable format %d", format);
}
const unsigned header_end = static_cast<unsigned>(subtable.offset());
if (header_end > std::numeric_limits<uint16_t>::max()) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad mark attachment subtable size ending at %d", header_end);
}
if (offset_coverage1 < header_end || offset_coverage1 >= length) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad coverage 1 offset %d", offset_coverage1);
}
if (!ots::ParseCoverageTable(data + offset_coverage1,
if (!ots::ParseCoverageTable(file, data + offset_coverage1,
length - offset_coverage1,
file->maxp->num_glyphs)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse converge 1 table");
}
if (offset_coverage2 < header_end || offset_coverage2 >= length) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad coverage 2 offset %d", offset_coverage2);
}
if (!ots::ParseCoverageTable(data + offset_coverage2,
if (!ots::ParseCoverageTable(file, data + offset_coverage2,
length - offset_coverage2,
file->maxp->num_glyphs)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse coverage table 2");
}
if (offset_mark_array < header_end || offset_mark_array >= length) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad mark array offset %d", offset_mark_array);
}
if (!ParseMarkArrayTable(data + offset_mark_array,
if (!ParseMarkArrayTable(file, data + offset_mark_array,
length - offset_mark_array, class_count)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse mark array");
}
if (offset_type_specific_array < header_end ||
offset_type_specific_array >= length) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad type specific array offset %d", offset_type_specific_array);
}
if (type == GPOS_TYPE_MARK_TO_BASE_ATTACHMENT ||
type == GPOS_TYPE_MARK_TO_MARK_ATTACHMENT) {
if (!ParseAnchorArrayTable(data + offset_type_specific_array,
if (!ParseAnchorArrayTable(file, data + offset_type_specific_array,
length - offset_type_specific_array,
class_count)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse anchor array");
}
} else if (type == GPOS_TYPE_MARK_TO_LIGATURE_ATTACHMENT) {
if (!ParseLigatureArrayTable(data + offset_type_specific_array,
if (!ParseLigatureArrayTable(file, data + offset_type_specific_array,
length - offset_type_specific_array,
class_count)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse ligature array");
}
} else {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad attachment type %d", type);
}
return true;
@ -647,7 +652,7 @@ bool ParseMarkToMarkAttachment(const ots::OpenTypeFile *file,
// Contextual Positioning Subtables
bool ParseContextPositioning(const ots::OpenTypeFile *file,
const uint8_t *data, const size_t length) {
return ots::ParseContextSubtable(data, length, file->maxp->num_glyphs,
return ots::ParseContextSubtable(file, data, length, file->maxp->num_glyphs,
file->gpos->num_lookups);
}
@ -655,7 +660,7 @@ bool ParseContextPositioning(const ots::OpenTypeFile *file,
// Chaining Contexual Positioning Subtable
bool ParseChainedContextPositioning(const ots::OpenTypeFile *file,
const uint8_t *data, const size_t length) {
return ots::ParseChainingContextSubtable(data, length,
return ots::ParseChainingContextSubtable(file, data, length,
file->maxp->num_glyphs,
file->gpos->num_lookups);
}
@ -670,11 +675,11 @@ bool ParseExtensionPositioning(const ots::OpenTypeFile *file,
} // namespace
#define DROP_THIS_TABLE \
#define DROP_THIS_TABLE(msg_) \
do { \
file->gpos->data = 0; \
file->gpos->length = 0; \
OTS_FAILURE_MSG("OpenType layout data discarded"); \
OTS_FAILURE_MSG(msg_ ", table discarded"); \
} while (0)
namespace ots {
@ -728,7 +733,7 @@ namespace ots {
bool ots_gpos_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
// Parsing GPOS table requires num_glyphs which is contained in maxp table.
if (!file->maxp) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("missing maxp table needed in GPOS");
}
Buffer table(data, length);
@ -744,14 +749,12 @@ bool ots_gpos_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
!table.ReadU16(&offset_script_list) ||
!table.ReadU16(&offset_feature_list) ||
!table.ReadU16(&offset_lookup_list)) {
OTS_WARNING("incomplete GPOS table");
DROP_THIS_TABLE;
DROP_THIS_TABLE("Incomplete table");
return true;
}
if (version != 0x00010000) {
OTS_WARNING("bad GPOS version");
DROP_THIS_TABLE;
DROP_THIS_TABLE("Bad version");
return true;
}
if ((offset_script_list < kGposHeaderSize ||
@ -760,8 +763,7 @@ bool ots_gpos_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
offset_feature_list >= length) ||
(offset_lookup_list < kGposHeaderSize ||
offset_lookup_list >= length)) {
OTS_WARNING("bad offset in GPOS header");
DROP_THIS_TABLE;
DROP_THIS_TABLE("Bad offset in table header");
return true;
}
@ -769,24 +771,21 @@ bool ots_gpos_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
length - offset_lookup_list,
&kGposLookupSubtableParser,
&gpos->num_lookups)) {
OTS_WARNING("failed to parse lookup list table");
DROP_THIS_TABLE;
DROP_THIS_TABLE("Failed to parse lookup list table");
return true;
}
uint16_t num_features = 0;
if (!ParseFeatureListTable(data + offset_feature_list,
if (!ParseFeatureListTable(file, data + offset_feature_list,
length - offset_feature_list, gpos->num_lookups,
&num_features)) {
OTS_WARNING("failed to parse feature list table");
DROP_THIS_TABLE;
DROP_THIS_TABLE("Failed to parse feature list table");
return true;
}
if (!ParseScriptListTable(data + offset_script_list,
if (!ParseScriptListTable(file, data + offset_script_list,
length - offset_script_list, num_features)) {
OTS_WARNING("failed to parse script list table");
DROP_THIS_TABLE;
DROP_THIS_TABLE("Failed to parse script list table");
return true;
}
@ -796,16 +795,12 @@ bool ots_gpos_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
}
bool ots_gpos_should_serialise(OpenTypeFile *file) {
const bool needed_tables_dropped =
(file->gdef && file->gdef->data == NULL) ||
(file->gsub && file->gsub->data == NULL);
return file->gpos != NULL && file->gpos->data != NULL &&
!needed_tables_dropped;
return file->gpos != NULL && file->gpos->data != NULL;
}
bool ots_gpos_serialise(OTSStream *out, OpenTypeFile *file) {
if (!out->Write(file->gpos->data, file->gpos->length)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write GPOS table");
}
return true;

View File

@ -1,181 +0,0 @@
// Copyright (c) 2010 Mozilla Foundation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "graphite.h"
// Support for preserving (NOT sanitizing) the Graphite tables
namespace ots {
// 'Silf'
bool ots_silf_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
Buffer table(data, length);
OpenTypeSILF *silf = new OpenTypeSILF;
file->silf = silf;
if (!table.Skip(length)) {
return OTS_FAILURE();
}
silf->data = data;
silf->length = length;
return true;
}
bool ots_silf_should_serialise(OpenTypeFile *file) {
return file->preserve_graphite && file->silf;
}
bool ots_silf_serialise(OTSStream *out, OpenTypeFile *file) {
const OpenTypeSILF *silf = file->silf;
if (!out->Write(silf->data, silf->length)) {
return OTS_FAILURE();
}
return true;
}
void ots_silf_free(OpenTypeFile *file) {
delete file->silf;
}
// 'Sill'
bool ots_sill_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
Buffer table(data, length);
OpenTypeSILL *sill = new OpenTypeSILL;
file->sill = sill;
if (!table.Skip(length)) {
return OTS_FAILURE();
}
sill->data = data;
sill->length = length;
return true;
}
bool ots_sill_should_serialise(OpenTypeFile *file) {
return file->preserve_graphite && file->sill;
}
bool ots_sill_serialise(OTSStream *out, OpenTypeFile *file) {
const OpenTypeSILL *sill = file->sill;
if (!out->Write(sill->data, sill->length)) {
return OTS_FAILURE();
}
return true;
}
void ots_sill_free(OpenTypeFile *file) {
delete file->sill;
}
// 'Gloc'
bool ots_gloc_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
Buffer table(data, length);
OpenTypeGLOC *gloc = new OpenTypeGLOC;
file->gloc = gloc;
if (!table.Skip(length)) {
return OTS_FAILURE();
}
gloc->data = data;
gloc->length = length;
return true;
}
bool ots_gloc_should_serialise(OpenTypeFile *file) {
return file->preserve_graphite && file->gloc;
}
bool ots_gloc_serialise(OTSStream *out, OpenTypeFile *file) {
const OpenTypeGLOC *gloc = file->gloc;
if (!out->Write(gloc->data, gloc->length)) {
return OTS_FAILURE();
}
return true;
}
void ots_gloc_free(OpenTypeFile *file) {
delete file->gloc;
}
// 'Glat'
bool ots_glat_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
Buffer table(data, length);
OpenTypeGLAT *glat = new OpenTypeGLAT;
file->glat = glat;
if (!table.Skip(length)) {
return OTS_FAILURE();
}
glat->data = data;
glat->length = length;
return true;
}
bool ots_glat_should_serialise(OpenTypeFile *file) {
return file->preserve_graphite && file->glat;
}
bool ots_glat_serialise(OTSStream *out, OpenTypeFile *file) {
const OpenTypeGLAT *glat = file->glat;
if (!out->Write(glat->data, glat->length)) {
return OTS_FAILURE();
}
return true;
}
void ots_glat_free(OpenTypeFile *file) {
delete file->glat;
}
// 'Feat'
bool ots_feat_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
Buffer table(data, length);
OpenTypeFEAT *feat = new OpenTypeFEAT;
file->feat = feat;
if (!table.Skip(length)) {
return OTS_FAILURE();
}
feat->data = data;
feat->length = length;
return true;
}
bool ots_feat_should_serialise(OpenTypeFile *file) {
return file->preserve_graphite && file->feat;
}
bool ots_feat_serialise(OTSStream *out, OpenTypeFile *file) {
const OpenTypeFEAT *feat = file->feat;
if (!out->Write(feat->data, feat->length)) {
return OTS_FAILURE();
}
return true;
}
void ots_feat_free(OpenTypeFile *file) {
delete file->feat;
}
} // namespace ots

View File

@ -1,39 +0,0 @@
// Copyright (c) 2010 Mozilla Foundation. 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_GRAPHITE_H_
#define OTS_GRAPHITE_H_
#include "ots.h"
namespace ots {
struct OpenTypeSILF {
const uint8_t *data;
uint32_t length;
};
struct OpenTypeSILL {
const uint8_t *data;
uint32_t length;
};
struct OpenTypeGLOC {
const uint8_t *data;
uint32_t length;
};
struct OpenTypeGLAT {
const uint8_t *data;
uint32_t length;
};
struct OpenTypeFEAT {
const uint8_t *data;
uint32_t length;
};
} // namespace ots
#endif // OTS_GRAPHITE_H_

View File

@ -7,8 +7,6 @@
#include <limits>
#include <vector>
#include "gdef.h"
#include "gpos.h"
#include "layout.h"
#include "maxp.h"
@ -20,7 +18,7 @@
namespace {
// The GSUB header size
const size_t kGsubHeaderSize = 8;
const size_t kGsubHeaderSize = 4 + 3 * 2;
enum GSUB_TYPE {
GSUB_TYPE_SINGLE = 1,
@ -65,9 +63,8 @@ const ots::LookupSubtableParser::TypeParser kGsubTypeParsers[] = {
ParseReverseChainingContextSingleSubstitution}
};
// TODO(bashi): Port Chromium's arraysize macro and use it instead of sizeof().
const ots::LookupSubtableParser kGsubLookupSubtableParser = {
sizeof(kGsubTypeParsers) / sizeof(kGsubTypeParsers[0]),
arraysize(kGsubTypeParsers),
GSUB_TYPE_EXTENSION_SUBSTITUTION, kGsubTypeParsers
};
@ -82,7 +79,7 @@ bool ParseSingleSubstitution(const ots::OpenTypeFile *file,
if (!subtable.ReadU16(&format) ||
!subtable.ReadU16(&offset_coverage)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read single subst table header");
}
const uint16_t num_glyphs = file->maxp->num_glyphs;
@ -90,63 +87,63 @@ bool ParseSingleSubstitution(const ots::OpenTypeFile *file,
// Parse SingleSubstFormat1
int16_t delta_glyph_id = 0;
if (!subtable.ReadS16(&delta_glyph_id)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read glyph shift from format 1 single subst table");
}
if (std::abs(delta_glyph_id) >= num_glyphs) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("bad glyph shift of %d in format 1 single subst table", delta_glyph_id);
}
} else if (format == 2) {
// Parse SingleSubstFormat2
uint16_t glyph_count = 0;
if (!subtable.ReadU16(&glyph_count)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read glyph cound in format 2 single subst table");
}
if (glyph_count > num_glyphs) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad glyph count %d > %d in format 2 single subst table", glyph_count, num_glyphs);
}
for (unsigned i = 0; i < glyph_count; ++i) {
uint16_t substitute = 0;
if (!subtable.ReadU16(&substitute)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read substitution %d in format 2 single subst table", i);
}
if (substitute >= num_glyphs) {
OTS_WARNING("too large substitute: %u", substitute);
return OTS_FAILURE();
return OTS_FAILURE_MSG("too large substitute: %u", substitute);
}
}
} else {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad single subst table format %d", format);
}
if (offset_coverage < subtable.offset() || offset_coverage >= length) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad coverage offset %x", offset_coverage);
}
if (!ots::ParseCoverageTable(data + offset_coverage,
if (!ots::ParseCoverageTable(file, data + offset_coverage,
length - offset_coverage, num_glyphs)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse coverage table");
}
return true;
}
bool ParseSequenceTable(const uint8_t *data, const size_t length,
bool ParseSequenceTable(const ots::OpenTypeFile *file,
const uint8_t *data, const size_t length,
const uint16_t num_glyphs) {
ots::Buffer subtable(data, length);
uint16_t glyph_count = 0;
if (!subtable.ReadU16(&glyph_count)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read glyph count in sequence table");
}
if (glyph_count > num_glyphs) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("bad glyph count %d > %d", glyph_count, num_glyphs);
}
for (unsigned i = 0; i < glyph_count; ++i) {
uint16_t substitute = 0;
if (!subtable.ReadU16(&substitute)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failedt o read substitution %d in sequence table", i);
}
if (substitute >= num_glyphs) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad subsitution (%d) %d > %d", i, substitute, num_glyphs);
}
}
@ -166,63 +163,63 @@ bool ParseMutipleSubstitution(const ots::OpenTypeFile *file,
if (!subtable.ReadU16(&format) ||
!subtable.ReadU16(&offset_coverage) ||
!subtable.ReadU16(&sequence_count)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read header of multiple subst table");
}
if (format != 1) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad multiple subst table format %d", format);
}
const uint16_t num_glyphs = file->maxp->num_glyphs;
const unsigned sequence_end = static_cast<unsigned>(6) +
sequence_count * 2;
if (sequence_end > std::numeric_limits<uint16_t>::max()) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad segence end %d, in multiple subst", sequence_end);
}
for (unsigned i = 0; i < sequence_count; ++i) {
uint16_t offset_sequence = 0;
if (!subtable.ReadU16(&offset_sequence)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read sequence offset for sequence %d", i);
}
if (offset_sequence < sequence_end || offset_sequence >= length) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad sequence offset %d for sequence %d", offset_sequence, i);
}
if (!ParseSequenceTable(data + offset_sequence, length - offset_sequence,
if (!ParseSequenceTable(file, data + offset_sequence, length - offset_sequence,
num_glyphs)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse sequence table %d", i);
}
}
if (offset_coverage < sequence_end || offset_coverage >= length) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad coverage offset %d", offset_coverage);
}
if (!ots::ParseCoverageTable(data + offset_coverage,
if (!ots::ParseCoverageTable(file, data + offset_coverage,
length - offset_coverage, num_glyphs)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse coverage table");
}
return true;
}
bool ParseAlternateSetTable(const uint8_t *data, const size_t length,
bool ParseAlternateSetTable(const ots::OpenTypeFile *file,
const uint8_t *data, const size_t length,
const uint16_t num_glyphs) {
ots::Buffer subtable(data, length);
uint16_t glyph_count = 0;
if (!subtable.ReadU16(&glyph_count)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read alternate set header");
}
if (glyph_count > num_glyphs) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad glyph count %d > %d in alternate set table", glyph_count, num_glyphs);
}
for (unsigned i = 0; i < glyph_count; ++i) {
uint16_t alternate = 0;
if (!subtable.ReadU16(&alternate)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read alternate %d", i);
}
if (alternate >= num_glyphs) {
OTS_WARNING("too large alternate: %u", alternate);
return OTS_FAILURE();
return OTS_FAILURE_MSG("Too large alternate: %u", alternate);
}
}
return true;
@ -241,47 +238,48 @@ bool ParseAlternateSubstitution(const ots::OpenTypeFile *file,
if (!subtable.ReadU16(&format) ||
!subtable.ReadU16(&offset_coverage) ||
!subtable.ReadU16(&alternate_set_count)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read alternate subst header");
}
if (format != 1) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad alternate subst table format %d", format);
}
const uint16_t num_glyphs = file->maxp->num_glyphs;
const unsigned alternate_set_end = static_cast<unsigned>(6) +
alternate_set_count * 2;
if (alternate_set_end > std::numeric_limits<uint16_t>::max()) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad end of alternate set %d", alternate_set_end);
}
for (unsigned i = 0; i < alternate_set_count; ++i) {
uint16_t offset_alternate_set = 0;
if (!subtable.ReadU16(&offset_alternate_set)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read alternate set offset for set %d", i);
}
if (offset_alternate_set < alternate_set_end ||
offset_alternate_set >= length) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad alternate set offset %d for set %d", offset_alternate_set, i);
}
if (!ParseAlternateSetTable(data + offset_alternate_set,
if (!ParseAlternateSetTable(file, data + offset_alternate_set,
length - offset_alternate_set,
num_glyphs)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse alternate set");
}
}
if (offset_coverage < alternate_set_end || offset_coverage >= length) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad coverage offset %d", offset_coverage);
}
if (!ots::ParseCoverageTable(data + offset_coverage,
if (!ots::ParseCoverageTable(file, data + offset_coverage,
length - offset_coverage, num_glyphs)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse coverage table");
}
return true;
}
bool ParseLigatureTable(const uint8_t *data, const size_t length,
bool ParseLigatureTable(const ots::OpenTypeFile *file,
const uint8_t *data, const size_t length,
const uint16_t num_glyphs) {
ots::Buffer subtable(data, length);
@ -290,54 +288,54 @@ bool ParseLigatureTable(const uint8_t *data, const size_t length,
if (!subtable.ReadU16(&lig_glyph) ||
!subtable.ReadU16(&comp_count)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read ligatuer table header");
}
if (lig_glyph >= num_glyphs) {
OTS_WARNING("too large lig_glyph: %u", lig_glyph);
return OTS_FAILURE();
return OTS_FAILURE_MSG("too large lig_glyph: %u", lig_glyph);
}
if (comp_count == 0 || comp_count > num_glyphs) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad component count of %d", comp_count);
}
for (unsigned i = 0; i < comp_count - static_cast<unsigned>(1); ++i) {
uint16_t component = 0;
if (!subtable.ReadU16(&component)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read ligature component %d", i);
}
if (component >= num_glyphs) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad ligature component %d of %d", i, component);
}
}
return true;
}
bool ParseLigatureSetTable(const uint8_t *data, const size_t length,
bool ParseLigatureSetTable(const ots::OpenTypeFile *file,
const uint8_t *data, const size_t length,
const uint16_t num_glyphs) {
ots::Buffer subtable(data, length);
uint16_t ligature_count = 0;
if (!subtable.ReadU16(&ligature_count)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read ligature count in ligature set");
}
const unsigned ligature_end = static_cast<unsigned>(2) + ligature_count * 2;
if (ligature_end > std::numeric_limits<uint16_t>::max()) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad end of ligature %d in ligature set", ligature_end);
}
for (unsigned i = 0; i < ligature_count; ++i) {
uint16_t offset_ligature = 0;
if (!subtable.ReadU16(&offset_ligature)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read ligature offset %d", i);
}
if (offset_ligature < ligature_end || offset_ligature >= length) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad ligature offset %d for ligature %d", offset_ligature, i);
}
if (!ParseLigatureTable(data + offset_ligature, length - offset_ligature,
if (!ParseLigatureTable(file, data + offset_ligature, length - offset_ligature,
num_glyphs)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse ligature %d", i);
}
}
@ -357,40 +355,40 @@ bool ParseLigatureSubstitution(const ots::OpenTypeFile *file,
if (!subtable.ReadU16(&format) ||
!subtable.ReadU16(&offset_coverage) ||
!subtable.ReadU16(&lig_set_count)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read ligature substitution header");
}
if (format != 1) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad ligature substitution table format %d", format);
}
const uint16_t num_glyphs = file->maxp->num_glyphs;
const unsigned ligature_set_end = static_cast<unsigned>(6) +
lig_set_count * 2;
if (ligature_set_end > std::numeric_limits<uint16_t>::max()) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad end of ligature set %d in ligature substitution table", ligature_set_end);
}
for (unsigned i = 0; i < lig_set_count; ++i) {
uint16_t offset_ligature_set = 0;
if (!subtable.ReadU16(&offset_ligature_set)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read ligature set offset %d", i);
}
if (offset_ligature_set < ligature_set_end ||
offset_ligature_set >= length) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad ligature set offset %d for set %d", offset_ligature_set, i);
}
if (!ParseLigatureSetTable(data + offset_ligature_set,
if (!ParseLigatureSetTable(file, data + offset_ligature_set,
length - offset_ligature_set, num_glyphs)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse ligature set %d", i);
}
}
if (offset_coverage < ligature_set_end || offset_coverage >= length) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad coverage offset %d", offset_coverage);
}
if (!ots::ParseCoverageTable(data + offset_coverage,
if (!ots::ParseCoverageTable(file, data + offset_coverage,
length - offset_coverage, num_glyphs)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse coverage table");
}
return true;
@ -400,7 +398,7 @@ bool ParseLigatureSubstitution(const ots::OpenTypeFile *file,
// Contextual Substitution Subtable
bool ParseContextSubstitution(const ots::OpenTypeFile *file,
const uint8_t *data, const size_t length) {
return ots::ParseContextSubtable(data, length, file->maxp->num_glyphs,
return ots::ParseContextSubtable(file, data, length, file->maxp->num_glyphs,
file->gsub->num_lookups);
}
@ -409,7 +407,7 @@ bool ParseContextSubstitution(const ots::OpenTypeFile *file,
bool ParseChainingContextSubstitution(const ots::OpenTypeFile *file,
const uint8_t *data,
const size_t length) {
return ots::ParseChainingContextSubtable(data, length,
return ots::ParseChainingContextSubtable(file, data, length,
file->maxp->num_glyphs,
file->gsub->num_lookups);
}
@ -433,95 +431,95 @@ bool ParseReverseChainingContextSingleSubstitution(
if (!subtable.ReadU16(&format) ||
!subtable.ReadU16(&offset_coverage)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read reverse chaining header");
}
const uint16_t num_glyphs = file->maxp->num_glyphs;
uint16_t backtrack_glyph_count = 0;
if (!subtable.ReadU16(&backtrack_glyph_count)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read backtrack glyph count in reverse chaining table");
}
if (backtrack_glyph_count > num_glyphs) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad backtrack glyph count of %d", backtrack_glyph_count);
}
std::vector<uint16_t> offsets_backtrack;
offsets_backtrack.reserve(backtrack_glyph_count);
for (unsigned i = 0; i < backtrack_glyph_count; ++i) {
uint16_t offset = 0;
if (!subtable.ReadU16(&offset)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read backtrack offset %d", i);
}
offsets_backtrack.push_back(offset);
}
uint16_t lookahead_glyph_count = 0;
if (!subtable.ReadU16(&lookahead_glyph_count)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read look ahead glyph count");
}
if (lookahead_glyph_count > num_glyphs) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad look ahead glyph count %d", lookahead_glyph_count);
}
std::vector<uint16_t> offsets_lookahead;
offsets_lookahead.reserve(lookahead_glyph_count);
for (unsigned i = 0; i < lookahead_glyph_count; ++i) {
uint16_t offset = 0;
if (!subtable.ReadU16(&offset)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read look ahead offset %d", i);
}
offsets_lookahead.push_back(offset);
}
uint16_t glyph_count = 0;
if (!subtable.ReadU16(&glyph_count)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read glyph count in reverse chaining table");
}
if (glyph_count > num_glyphs) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad glyph count of %d", glyph_count);
}
for (unsigned i = 0; i < glyph_count; ++i) {
uint16_t substitute = 0;
if (!subtable.ReadU16(&substitute)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read substitution %d reverse chaining table", i);
}
if (substitute >= num_glyphs) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad substitute glyph %d in reverse chaining table substitution %d", substitute, i);
}
}
const unsigned substitute_end = static_cast<unsigned>(10) +
(backtrack_glyph_count + lookahead_glyph_count + glyph_count) * 2;
if (substitute_end > std::numeric_limits<uint16_t>::max()) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad substitute end offset in reverse chaining table");
}
if (offset_coverage < substitute_end || offset_coverage >= length) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad coverage offset %d in reverse chaining table", offset_coverage);
}
if (!ots::ParseCoverageTable(data + offset_coverage,
if (!ots::ParseCoverageTable(file, data + offset_coverage,
length - offset_coverage, num_glyphs)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse coverage table in reverse chaining table");
}
for (unsigned i = 0; i < backtrack_glyph_count; ++i) {
if (offsets_backtrack[i] < substitute_end ||
offsets_backtrack[i] >= length) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad backtrack offset %d for backtrack %d in reverse chaining table", offsets_backtrack[i], i);
}
if (!ots::ParseCoverageTable(data + offsets_backtrack[i],
if (!ots::ParseCoverageTable(file, data + offsets_backtrack[i],
length - offsets_backtrack[i], num_glyphs)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse coverage table for backtrack %d in reverse chaining table", i);
}
}
for (unsigned i = 0; i < lookahead_glyph_count; ++i) {
if (offsets_lookahead[i] < substitute_end ||
offsets_lookahead[i] >= length) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad lookahead offset %d for lookahead %d in reverse chaining table", offsets_lookahead[i], i);
}
if (!ots::ParseCoverageTable(data + offsets_lookahead[i],
if (!ots::ParseCoverageTable(file, data + offsets_lookahead[i],
length - offsets_lookahead[i], num_glyphs)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse lookahead coverage table %d in reverse chaining table", i);
}
}
@ -530,11 +528,11 @@ bool ParseReverseChainingContextSingleSubstitution(
} // namespace
#define DROP_THIS_TABLE \
#define DROP_THIS_TABLE(msg_) \
do { \
file->gsub->data = 0; \
file->gsub->length = 0; \
OTS_FAILURE_MSG("OpenType layout data discarded"); \
OTS_FAILURE_MSG(msg_ ", table discarded"); \
} while (0)
namespace ots {
@ -592,7 +590,7 @@ namespace ots {
bool ots_gsub_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
// Parsing gsub table requires |file->maxp->num_glyphs|
if (!file->maxp) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Missing maxp table in font, needed by GSUB");
}
Buffer table(data, length);
@ -608,14 +606,12 @@ bool ots_gsub_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
!table.ReadU16(&offset_script_list) ||
!table.ReadU16(&offset_feature_list) ||
!table.ReadU16(&offset_lookup_list)) {
OTS_WARNING("incomplete GSUB table");
DROP_THIS_TABLE;
DROP_THIS_TABLE("Incomplete table");
return true;
}
if (version != 0x00010000) {
OTS_WARNING("bad GSUB version");
DROP_THIS_TABLE;
DROP_THIS_TABLE("Bad version");
return true;
}
if ((offset_script_list < kGsubHeaderSize ||
@ -624,8 +620,7 @@ bool ots_gsub_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
offset_feature_list >= length) ||
(offset_lookup_list < kGsubHeaderSize ||
offset_lookup_list >= length)) {
OTS_WARNING("bad offset in GSUB header");
DROP_THIS_TABLE;
DROP_THIS_TABLE("Bad offset in table header");
return true;
}
@ -633,24 +628,21 @@ bool ots_gsub_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
length - offset_lookup_list,
&kGsubLookupSubtableParser,
&gsub->num_lookups)) {
OTS_WARNING("failed to parse lookup list table");
DROP_THIS_TABLE;
DROP_THIS_TABLE("Failed to parse lookup list table");
return true;
}
uint16_t num_features = 0;
if (!ParseFeatureListTable(data + offset_feature_list,
if (!ParseFeatureListTable(file, data + offset_feature_list,
length - offset_feature_list, gsub->num_lookups,
&num_features)) {
OTS_WARNING("failed to parse feature list table");
DROP_THIS_TABLE;
DROP_THIS_TABLE("Failed to parse feature list table");
return true;
}
if (!ParseScriptListTable(data + offset_script_list,
if (!ParseScriptListTable(file, data + offset_script_list,
length - offset_script_list, num_features)) {
OTS_WARNING("failed to parse script list table");
DROP_THIS_TABLE;
DROP_THIS_TABLE("Failed to parse script list table");
return true;
}
@ -660,16 +652,12 @@ bool ots_gsub_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
}
bool ots_gsub_should_serialise(OpenTypeFile *file) {
const bool needed_tables_dropped =
(file->gdef && file->gdef->data == NULL) ||
(file->gpos && file->gpos->data == NULL);
return file->gsub != NULL && file->gsub->data != NULL
&& !needed_tables_dropped;
return file->gsub != NULL && file->gsub->data != NULL;
}
bool ots_gsub_serialise(OTSStream *out, OpenTypeFile *file) {
if (!out->Write(file->gsub->data, file->gsub->length)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write GSUB table");
}
return true;

View File

@ -7,10 +7,16 @@
#include "maxp.h"
// hdmx - Horizontal Device Metrics
// http://www.microsoft.com/opentype/otspec/hdmx.htm
// http://www.microsoft.com/typography/otspec/hdmx.htm
#define TABLE_NAME "hdmx"
#define DROP_THIS_TABLE \
do { delete file->hdmx; file->hdmx = 0; } while (0)
do { \
delete file->hdmx; \
file->hdmx = 0; \
OTS_FAILURE_MSG("Table discarded"); \
} while (0)
namespace ots {
@ -20,7 +26,7 @@ bool ots_hdmx_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
OpenTypeHDMX * const hdmx = file->hdmx;
if (!file->head || !file->maxp) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Missing maxp or head tables in font, needed by hdmx");
}
if ((file->head->flags & 0x14) == 0) {
@ -35,7 +41,7 @@ bool ots_hdmx_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
if (!table.ReadU16(&hdmx->version) ||
!table.ReadS16(&num_recs) ||
!table.ReadS32(&hdmx->size_device_record)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read hdmx header");
}
if (hdmx->version != 0) {
OTS_WARNING("bad version: %u", hdmx->version);
@ -56,7 +62,7 @@ bool ots_hdmx_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
hdmx->pad_len = hdmx->size_device_record - actual_size_device_record;
if (hdmx->pad_len > 3) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad padding %d", hdmx->pad_len);
}
uint8_t last_pixel_size = 0;
@ -66,7 +72,7 @@ bool ots_hdmx_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
if (!table.ReadU8(&rec.pixel_size) ||
!table.ReadU8(&rec.max_width)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read hdmx record %d", i);
}
if ((i != 0) &&
(rec.pixel_size <= last_pixel_size)) {
@ -80,14 +86,14 @@ bool ots_hdmx_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
for (unsigned j = 0; j < file->maxp->num_glyphs; ++j) {
uint8_t width;
if (!table.ReadU8(&width)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read glyph width %d in record %d", j, i);
}
rec.widths.push_back(width);
}
if ((hdmx->pad_len > 0) &&
!table.Skip(hdmx->pad_len)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to skip padding %d", hdmx->pad_len);
}
hdmx->records.push_back(rec);
@ -108,7 +114,7 @@ bool ots_hdmx_serialise(OTSStream *out, OpenTypeFile *file) {
if (!out->WriteU16(hdmx->version) ||
!out->WriteS16(hdmx->records.size()) ||
!out->WriteS32(hdmx->size_device_record)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write hdmx header");
}
for (unsigned i = 0; i < hdmx->records.size(); ++i) {
@ -116,11 +122,11 @@ bool ots_hdmx_serialise(OTSStream *out, OpenTypeFile *file) {
if (!out->Write(&rec.pixel_size, 1) ||
!out->Write(&rec.max_width, 1) ||
!out->Write(&rec.widths[0], rec.widths.size())) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write hdmx record %d", i);
}
if ((hdmx->pad_len > 0) &&
!out->Write((const uint8_t *)"\x00\x00\x00", hdmx->pad_len)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write hdmx padding of length %d", hdmx->pad_len);
}
}

View File

@ -7,7 +7,9 @@
#include <cstring>
// head - Font Header
// http://www.microsoft.com/opentype/otspec/head.htm
// http://www.microsoft.com/typography/otspec/head.htm
#define TABLE_NAME "head"
namespace ots {
@ -18,39 +20,39 @@ bool ots_head_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
uint32_t version = 0;
if (!table.ReadU32(&version) ||
!table.ReadU32(&file->head->revision)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read head header");
}
if (version >> 16 != 1) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad head table version of %d", version);
}
// Skip the checksum adjustment
if (!table.Skip(4)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read checksum");
}
uint32_t magic;
if (!table.ReadTag(&magic) ||
std::memcmp(&magic, "\x5F\x0F\x3C\xF5", 4)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read font magic number");
}
if (!table.ReadU16(&file->head->flags)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read head flags");
}
// We allow bits 0..4, 11..13
file->head->flags &= 0x381f;
if (!table.ReadU16(&file->head->ppem)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read pixels per em");
}
// ppem must be in range
if (file->head->ppem < 16 ||
file->head->ppem > 16384) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad ppm of %d", file->head->ppem);
}
// ppem must be a power of two
@ -58,57 +60,57 @@ bool ots_head_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
// We don't call ots_failure() for now since lots of TrueType fonts are
// not following this rule. Putting OTS_WARNING here is too noisy.
if ((file->head->ppem - 1) & file->head->ppem) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("ppm not a power of two: %d", file->head->ppem);
}
#endif
if (!table.ReadR64(&file->head->created) ||
!table.ReadR64(&file->head->modified)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't read font dates");
}
if (!table.ReadS16(&file->head->xmin) ||
!table.ReadS16(&file->head->ymin) ||
!table.ReadS16(&file->head->xmax) ||
!table.ReadS16(&file->head->ymax)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read font bounding box");
}
if (file->head->xmin > file->head->xmax) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad x dimension in the font bounding box (%d, %d)", file->head->xmin, file->head->xmax);
}
if (file->head->ymin > file->head->ymax) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad y dimension in the font bounding box (%d, %d)", file->head->ymin, file->head->ymax);
}
if (!table.ReadU16(&file->head->mac_style)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read font style");
}
// We allow bits 0..6
file->head->mac_style &= 0x7f;
if (!table.ReadU16(&file->head->min_ppem)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read font minimum ppm");
}
// We don't care about the font direction hint
if (!table.Skip(2)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to skip font direction hint");
}
if (!table.ReadS16(&file->head->index_to_loc_format)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read index to loc format");
}
if (file->head->index_to_loc_format < 0 ||
file->head->index_to_loc_format > 1) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad index to loc format %d", file->head->index_to_loc_format);
}
int16_t glyph_data_format;
if (!table.ReadS16(&glyph_data_format) ||
glyph_data_format) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read glyph data format");
}
return true;
@ -136,7 +138,7 @@ bool ots_head_serialise(OTSStream *out, OpenTypeFile *file) {
!out->WriteS16(2) ||
!out->WriteS16(file->head->index_to_loc_format) ||
!out->WriteS16(0)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write head table");
}
return true;

View File

@ -8,7 +8,9 @@
#include "maxp.h"
// hhea - Horizontal Header
// http://www.microsoft.com/opentype/otspec/hhea.htm
// http://www.microsoft.com/typography/otspec/hhea.htm
#define TABLE_NAME "hhea"
namespace ots {
@ -18,14 +20,14 @@ bool ots_hhea_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
file->hhea = hhea;
if (!table.ReadU32(&hhea->header.version)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read hhea version");
}
if (hhea->header.version >> 16 != 1) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad hhea version of %d", hhea->header.version);
}
if (!ParseMetricsHeader(file, &table, &hhea->header)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse horizontal metrics");
}
return true;
@ -36,8 +38,8 @@ bool ots_hhea_should_serialise(OpenTypeFile *file) {
}
bool ots_hhea_serialise(OTSStream *out, OpenTypeFile *file) {
if (!SerialiseMetricsHeader(out, &file->hhea->header)) {
return OTS_FAILURE();
if (!SerialiseMetricsHeader(file, out, &file->hhea->header)) {
return OTS_FAILURE_MSG("Failed to serialise horizontal metrics");
}
return true;
}

View File

@ -8,7 +8,9 @@
#include "maxp.h"
// hmtx - Horizontal Metrics
// http://www.microsoft.com/opentype/otspec/hmtx.htm
// http://www.microsoft.com/typography/otspec/hmtx.htm
#define TABLE_NAME "hmtx"
namespace ots {
@ -18,12 +20,12 @@ bool ots_hmtx_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
file->hmtx = hmtx;
if (!file->hhea || !file->maxp) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Missing hhea or maxp tables in font, needed by hmtx");
}
if (!ParseMetricsTable(&table, file->maxp->num_glyphs,
if (!ParseMetricsTable(file, &table, file->maxp->num_glyphs,
&file->hhea->header, &hmtx->metrics)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse hmtx metrics");
}
return true;
@ -34,8 +36,8 @@ bool ots_hmtx_should_serialise(OpenTypeFile *file) {
}
bool ots_hmtx_serialise(OTSStream *out, OpenTypeFile *file) {
if (!SerialiseMetricsTable(out, &file->hmtx->metrics)) {
return OTS_FAILURE();
if (!SerialiseMetricsTable(file, out, &file->hmtx->metrics)) {
return OTS_FAILURE_MSG("Failed to serialise htmx metrics");
}
return true;
}

View File

@ -5,10 +5,16 @@
#include "kern.h"
// kern - Kerning
// http://www.microsoft.com/opentype/otspec/kern.htm
// http://www.microsoft.com/typography/otspec/kern.htm
#define TABLE_NAME "kern"
#define DROP_THIS_TABLE \
do { delete file->kern; file->kern = 0; } while (0)
do { \
delete file->kern; \
file->kern = 0; \
OTS_FAILURE_MSG("Table discarded"); \
} while (0)
namespace ots {
@ -21,7 +27,7 @@ bool ots_kern_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
uint16_t num_tables = 0;
if (!table.ReadU16(&kern->version) ||
!table.ReadU16(&num_tables)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read kern header");
}
if (kern->version > 0) {
@ -42,7 +48,7 @@ bool ots_kern_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
if (!table.ReadU16(&subtable.version) ||
!table.ReadU16(&sub_length)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read kern subtable %d header", i);
}
if (subtable.version > 0) {
@ -52,11 +58,11 @@ bool ots_kern_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
const size_t current_offset = table.offset();
if (current_offset - 4 + sub_length > length) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad kern subtable %d offset %ld", i, current_offset);
}
if (!table.ReadU16(&subtable.coverage)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Cailed to read kern subtable %d coverage", i);
}
if (!(subtable.coverage & 0x1)) {
@ -81,7 +87,7 @@ bool ots_kern_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
!table.ReadU16(&subtable.search_range) ||
!table.ReadU16(&subtable.entry_selector) ||
!table.ReadU16(&subtable.range_shift)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read kern subtable %d format 0 fields", i);
}
if (!num_pairs) {
@ -109,7 +115,7 @@ bool ots_kern_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
subtable.search_range = expected_search_range;
}
if (subtable.entry_selector != max_pow2) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad subtable %d entry selector %d", i, subtable.entry_selector);
}
const uint32_t expected_range_shift
= kFormat0PairSize * num_pairs - subtable.search_range;
@ -126,7 +132,7 @@ bool ots_kern_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
if (!table.ReadU16(&kerning_pair.left) ||
!table.ReadU16(&kerning_pair.right) ||
!table.ReadS16(&kerning_pair.value)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read subtable %d kerning pair %d", i, j);
}
const uint32_t current_pair
= (kerning_pair.left << 16) + kerning_pair.right;
@ -163,7 +169,7 @@ bool ots_kern_serialise(OTSStream *out, OpenTypeFile *file) {
if (!out->WriteU16(kern->version) ||
!out->WriteU16(kern->subtables.size())) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't write kern table header");
}
for (unsigned i = 0; i < kern->subtables.size(); ++i) {
@ -175,13 +181,13 @@ bool ots_kern_serialise(OTSStream *out, OpenTypeFile *file) {
!out->WriteU16(kern->subtables[i].search_range) ||
!out->WriteU16(kern->subtables[i].entry_selector) ||
!out->WriteU16(kern->subtables[i].range_shift)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write kern subtable %d", i);
}
for (unsigned j = 0; j < kern->subtables[i].pairs.size(); ++j) {
if (!out->WriteU16(kern->subtables[i].pairs[j].left) ||
!out->WriteU16(kern->subtables[i].pairs[j].right) ||
!out->WriteS16(kern->subtables[i].pairs[j].value)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write kern pair %d for subtable %d", j, i);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -27,10 +27,12 @@ struct LookupSubtableParser {
const size_t length, const uint16_t lookup_type) const;
};
bool ParseScriptListTable(const uint8_t *data, const size_t length,
bool ParseScriptListTable(const ots::OpenTypeFile *file,
const uint8_t *data, const size_t length,
const uint16_t num_features);
bool ParseFeatureListTable(const uint8_t *data, const size_t length,
bool ParseFeatureListTable(const ots::OpenTypeFile *file,
const uint8_t *data, const size_t length,
const uint16_t num_lookups,
uint16_t *num_features);
@ -39,22 +41,28 @@ bool ParseLookupListTable(OpenTypeFile *file, const uint8_t *data,
const LookupSubtableParser* parser,
uint16_t* num_lookups);
bool ParseClassDefTable(const uint8_t *data, size_t length,
bool ParseClassDefTable(const ots::OpenTypeFile *file,
const uint8_t *data, size_t length,
const uint16_t num_glyphs,
const uint16_t num_classes);
bool ParseCoverageTable(const uint8_t *data, size_t length,
const uint16_t num_glyphs);
bool ParseCoverageTable(const ots::OpenTypeFile *file,
const uint8_t *data, size_t length,
const uint16_t num_glyphs,
const uint16_t expected_num_glyphs = 0);
bool ParseDeviceTable(const uint8_t *data, size_t length);
bool ParseDeviceTable(const ots::OpenTypeFile *file,
const uint8_t *data, size_t length);
// Parser for 'Contextual' subtable shared by GSUB/GPOS tables.
bool ParseContextSubtable(const uint8_t *data, const size_t length,
bool ParseContextSubtable(const ots::OpenTypeFile *file,
const uint8_t *data, const size_t length,
const uint16_t num_glyphs,
const uint16_t num_lookups);
// Parser for 'Chaining Contextual' subtable shared by GSUB/GPOS tables.
bool ParseChainingContextSubtable(const uint8_t *data, const size_t length,
bool ParseChainingContextSubtable(const ots::OpenTypeFile *file,
const uint8_t *data, const size_t length,
const uint16_t num_glyphs,
const uint16_t num_lookups);

View File

@ -8,7 +8,9 @@
#include "maxp.h"
// loca - Index to Location
// http://www.microsoft.com/opentype/otspec/loca.htm
// http://www.microsoft.com/typography/otspec/loca.htm
#define TABLE_NAME "loca"
namespace ots {
@ -22,7 +24,7 @@ bool ots_loca_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
file->loca = loca;
if (!file->maxp || !file->head) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("maxp or head tables missing from font, needed by loca");
}
const unsigned num_glyphs = file->maxp->num_glyphs;
@ -37,10 +39,10 @@ bool ots_loca_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
for (unsigned i = 0; i <= num_glyphs; ++i) {
uint16_t offset = 0;
if (!table.ReadU16(&offset)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read offset for glyph %d", i);
}
if (offset < last_offset) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Out of order offset %d < %d for glyph %d", offset, last_offset, i);
}
last_offset = offset;
loca->offsets[i] = offset * 2;
@ -49,10 +51,10 @@ bool ots_loca_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
for (unsigned i = 0; i <= num_glyphs; ++i) {
uint32_t offset = 0;
if (!table.ReadU32(&offset)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read offset for glyph %d", i);
}
if (offset < last_offset) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Out of order offset %d < %d for glyph %d", offset, last_offset, i);
}
last_offset = offset;
loca->offsets[i] = offset;
@ -71,19 +73,19 @@ bool ots_loca_serialise(OTSStream *out, OpenTypeFile *file) {
const OpenTypeHEAD *head = file->head;
if (!head) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Missing head table in font needed by loca");
}
if (head->index_to_loc_format == 0) {
for (unsigned i = 0; i < loca->offsets.size(); ++i) {
if (!out->WriteU16(loca->offsets[i] >> 1)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write glyph offset for glyph %d", i);
}
}
} else {
for (unsigned i = 0; i < loca->offsets.size(); ++i) {
if (!out->WriteU32(loca->offsets[i])) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write glyph offset for glyph %d", i);
}
}
}

View File

@ -9,8 +9,14 @@
// LTSH - Linear Threshold
// http://www.microsoft.com/typography/otspec/ltsh.htm
#define TABLE_NAME "LTSH"
#define DROP_THIS_TABLE \
do { delete file->ltsh; file->ltsh = 0; } while (0)
do { \
delete file->ltsh; \
file->ltsh = 0; \
OTS_FAILURE_MSG("Table discarded"); \
} while (0)
namespace ots {
@ -18,7 +24,7 @@ bool ots_ltsh_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
Buffer table(data, length);
if (!file->maxp) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Missing maxp table from font needed by ltsh");
}
OpenTypeLTSH *ltsh = new OpenTypeLTSH;
@ -27,7 +33,7 @@ bool ots_ltsh_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
uint16_t num_glyphs = 0;
if (!table.ReadU16(&ltsh->version) ||
!table.ReadU16(&num_glyphs)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read ltsh header");
}
if (ltsh->version != 0) {
@ -46,7 +52,7 @@ bool ots_ltsh_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
for (unsigned i = 0; i < num_glyphs; ++i) {
uint8_t pel = 0;
if (!table.ReadU8(&pel)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read pixels for glyph %d", i);
}
ltsh->ypels.push_back(pel);
}
@ -64,11 +70,11 @@ bool ots_ltsh_serialise(OTSStream *out, OpenTypeFile *file) {
if (!out->WriteU16(ltsh->version) ||
!out->WriteU16(ltsh->ypels.size())) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write pels size");
}
for (unsigned i = 0; i < ltsh->ypels.size(); ++i) {
if (!out->Write(&(ltsh->ypels[i]), 1)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write pixel size for glyph %d", i);
}
}

608
gfx/ots/src/math.cc Normal file
View File

@ -0,0 +1,608 @@
// Copyright (c) 2014 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.
// We use an underscore to avoid confusion with the standard math.h library.
#include "math_.h"
#include <limits>
#include <vector>
#include "layout.h"
#include "maxp.h"
// MATH - The MATH Table
// The specification is not yet public but has been submitted to the MPEG group
// in response to the 'Call for Proposals for ISO/IEC 14496-22 "Open Font
// Format" Color Font Technology and MATH layout support'. Meanwhile, you can
// contact Microsoft's engineer Murray Sargent to obtain a copy.
#define TABLE_NAME "MATH"
namespace {
// The size of MATH header.
// Version
// MathConstants
// MathGlyphInfo
// MathVariants
const unsigned kMathHeaderSize = 4 + 3 * 2;
// The size of the MathGlyphInfo header.
// MathItalicsCorrectionInfo
// MathTopAccentAttachment
// ExtendedShapeCoverage
// MathKernInfo
const unsigned kMathGlyphInfoHeaderSize = 4 * 2;
// The size of the MathValueRecord.
// Value
// DeviceTable
const unsigned kMathValueRecordSize = 2 * 2;
// The size of the GlyphPartRecord.
// glyph
// StartConnectorLength
// EndConnectorLength
// FullAdvance
// PartFlags
const unsigned kGlyphPartRecordSize = 5 * 2;
// Shared Table: MathValueRecord
bool ParseMathValueRecord(const ots::OpenTypeFile *file,
ots::Buffer* subtable, const uint8_t *data,
const size_t length) {
// Check the Value field.
if (!subtable->Skip(2)) {
return OTS_FAILURE();
}
// Check the offset to device table.
uint16_t offset = 0;
if (!subtable->ReadU16(&offset)) {
return OTS_FAILURE();
}
if (offset) {
if (offset >= length) {
return OTS_FAILURE();
}
if (!ots::ParseDeviceTable(file, data + offset, length - offset)) {
return OTS_FAILURE();
}
}
return true;
}
bool ParseMathConstantsTable(const ots::OpenTypeFile *file,
const uint8_t *data, size_t length) {
ots::Buffer subtable(data, length);
// Part 1: int16 or uint16 constants.
// ScriptPercentScaleDown
// ScriptScriptPercentScaleDown
// DelimitedSubFormulaMinHeight
// DisplayOperatorMinHeight
if (!subtable.Skip(4 * 2)) {
return OTS_FAILURE();
}
// Part 2: MathValueRecord constants.
// MathLeading
// AxisHeight
// AccentBaseHeight
// FlattenedAccentBaseHeight
// SubscriptShiftDown
// SubscriptTopMax
// SubscriptBaselineDropMin
// SuperscriptShiftUp
// SuperscriptShiftUpCramped
// SuperscriptBottomMin
//
// SuperscriptBaselineDropMax
// SubSuperscriptGapMin
// SuperscriptBottomMaxWithSubscript
// SpaceAfterScript
// UpperLimitGapMin
// UpperLimitBaselineRiseMin
// LowerLimitGapMin
// LowerLimitBaselineDropMin
// StackTopShiftUp
// StackTopDisplayStyleShiftUp
//
// StackBottomShiftDown
// StackBottomDisplayStyleShiftDown
// StackGapMin
// StackDisplayStyleGapMin
// StretchStackTopShiftUp
// StretchStackBottomShiftDown
// StretchStackGapAboveMin
// StretchStackGapBelowMin
// FractionNumeratorShiftUp
// FractionNumeratorDisplayStyleShiftUp
//
// FractionDenominatorShiftDown
// FractionDenominatorDisplayStyleShiftDown
// FractionNumeratorGapMin
// FractionNumDisplayStyleGapMin
// FractionRuleThickness
// FractionDenominatorGapMin
// FractionDenomDisplayStyleGapMin
// SkewedFractionHorizontalGap
// SkewedFractionVerticalGap
// OverbarVerticalGap
//
// OverbarRuleThickness
// OverbarExtraAscender
// UnderbarVerticalGap
// UnderbarRuleThickness
// UnderbarExtraDescender
// RadicalVerticalGap
// RadicalDisplayStyleVerticalGap
// RadicalRuleThickness
// RadicalExtraAscender
// RadicalKernBeforeDegree
//
// RadicalKernAfterDegree
for (unsigned i = 0; i < static_cast<unsigned>(51); ++i) {
if (!ParseMathValueRecord(file, &subtable, data, length)) {
return OTS_FAILURE();
}
}
// Part 3: uint16 constant
// RadicalDegreeBottomRaisePercent
if (!subtable.Skip(2)) {
return OTS_FAILURE();
}
return true;
}
bool ParseMathValueRecordSequenceForGlyphs(const ots::OpenTypeFile *file,
ots::Buffer* subtable,
const uint8_t *data,
const size_t length,
const uint16_t num_glyphs) {
// Check the header.
uint16_t offset_coverage = 0;
uint16_t sequence_count = 0;
if (!subtable->ReadU16(&offset_coverage) ||
!subtable->ReadU16(&sequence_count)) {
return OTS_FAILURE();
}
const unsigned sequence_end = static_cast<unsigned>(2 * 2) +
sequence_count * kMathValueRecordSize;
if (sequence_end > std::numeric_limits<uint16_t>::max()) {
return OTS_FAILURE();
}
// Check coverage table.
if (offset_coverage < sequence_end || offset_coverage >= length) {
return OTS_FAILURE();
}
if (!ots::ParseCoverageTable(file, data + offset_coverage,
length - offset_coverage,
num_glyphs, sequence_count)) {
return OTS_FAILURE();
}
// Check sequence.
for (unsigned i = 0; i < sequence_count; ++i) {
if (!ParseMathValueRecord(file, subtable, data, length)) {
return OTS_FAILURE();
}
}
return true;
}
bool ParseMathItalicsCorrectionInfoTable(const ots::OpenTypeFile *file,
const uint8_t *data,
size_t length,
const uint16_t num_glyphs) {
ots::Buffer subtable(data, length);
return ParseMathValueRecordSequenceForGlyphs(file, &subtable, data, length,
num_glyphs);
}
bool ParseMathTopAccentAttachmentTable(const ots::OpenTypeFile *file,
const uint8_t *data,
size_t length,
const uint16_t num_glyphs) {
ots::Buffer subtable(data, length);
return ParseMathValueRecordSequenceForGlyphs(file, &subtable, data, length,
num_glyphs);
}
bool ParseMathKernTable(const ots::OpenTypeFile *file,
const uint8_t *data, size_t length) {
ots::Buffer subtable(data, length);
// Check the Height count.
uint16_t height_count = 0;
if (!subtable.ReadU16(&height_count)) {
return OTS_FAILURE();
}
// Check the Correction Heights.
for (unsigned i = 0; i < height_count; ++i) {
if (!ParseMathValueRecord(file, &subtable, data, length)) {
return OTS_FAILURE();
}
}
// Check the Kern Values.
for (unsigned i = 0; i <= height_count; ++i) {
if (!ParseMathValueRecord(file, &subtable, data, length)) {
return OTS_FAILURE();
}
}
return true;
}
bool ParseMathKernInfoTable(const ots::OpenTypeFile *file,
const uint8_t *data, size_t length,
const uint16_t num_glyphs) {
ots::Buffer subtable(data, length);
// Check the header.
uint16_t offset_coverage = 0;
uint16_t sequence_count = 0;
if (!subtable.ReadU16(&offset_coverage) ||
!subtable.ReadU16(&sequence_count)) {
return OTS_FAILURE();
}
const unsigned sequence_end = static_cast<unsigned>(2 * 2) +
sequence_count * 4 * 2;
if (sequence_end > std::numeric_limits<uint16_t>::max()) {
return OTS_FAILURE();
}
// Check coverage table.
if (offset_coverage < sequence_end || offset_coverage >= length) {
return OTS_FAILURE();
}
if (!ots::ParseCoverageTable(file, data + offset_coverage, length - offset_coverage,
num_glyphs, sequence_count)) {
return OTS_FAILURE();
}
// Check sequence of MathKernInfoRecord
for (unsigned i = 0; i < sequence_count; ++i) {
// Check TopRight, TopLeft, BottomRight and BottomLeft Math Kern.
for (unsigned j = 0; j < 4; ++j) {
uint16_t offset_math_kern = 0;
if (!subtable.ReadU16(&offset_math_kern)) {
return OTS_FAILURE();
}
if (offset_math_kern) {
if (offset_math_kern < sequence_end || offset_math_kern >= length ||
!ParseMathKernTable(file, data + offset_math_kern,
length - offset_math_kern)) {
return OTS_FAILURE();
}
}
}
}
return true;
}
bool ParseMathGlyphInfoTable(const ots::OpenTypeFile *file,
const uint8_t *data, size_t length,
const uint16_t num_glyphs) {
ots::Buffer subtable(data, length);
// Check Header.
uint16_t offset_math_italics_correction_info = 0;
uint16_t offset_math_top_accent_attachment = 0;
uint16_t offset_extended_shaped_coverage = 0;
uint16_t offset_math_kern_info = 0;
if (!subtable.ReadU16(&offset_math_italics_correction_info) ||
!subtable.ReadU16(&offset_math_top_accent_attachment) ||
!subtable.ReadU16(&offset_extended_shaped_coverage) ||
!subtable.ReadU16(&offset_math_kern_info)) {
return OTS_FAILURE();
}
// Check subtables.
// The specification does not say whether the offsets for
// MathItalicsCorrectionInfo, MathTopAccentAttachment and MathKernInfo may
// be NULL, but that's the case in some fonts (e.g STIX) so we accept that.
if (offset_math_italics_correction_info) {
if (offset_math_italics_correction_info >= length ||
offset_math_italics_correction_info < kMathGlyphInfoHeaderSize ||
!ParseMathItalicsCorrectionInfoTable(
file, data + offset_math_italics_correction_info,
length - offset_math_italics_correction_info,
num_glyphs)) {
return OTS_FAILURE();
}
}
if (offset_math_top_accent_attachment) {
if (offset_math_top_accent_attachment >= length ||
offset_math_top_accent_attachment < kMathGlyphInfoHeaderSize ||
!ParseMathTopAccentAttachmentTable(file, data +
offset_math_top_accent_attachment,
length -
offset_math_top_accent_attachment,
num_glyphs)) {
return OTS_FAILURE();
}
}
if (offset_extended_shaped_coverage) {
if (offset_extended_shaped_coverage >= length ||
offset_extended_shaped_coverage < kMathGlyphInfoHeaderSize ||
!ots::ParseCoverageTable(file, data + offset_extended_shaped_coverage,
length - offset_extended_shaped_coverage,
num_glyphs)) {
return OTS_FAILURE();
}
}
if (offset_math_kern_info) {
if (offset_math_kern_info >= length ||
offset_math_kern_info < kMathGlyphInfoHeaderSize ||
!ParseMathKernInfoTable(file, data + offset_math_kern_info,
length - offset_math_kern_info, num_glyphs)) {
return OTS_FAILURE();
}
}
return true;
}
bool ParseGlyphAssemblyTable(const ots::OpenTypeFile *file,
const uint8_t *data,
size_t length, const uint16_t num_glyphs) {
ots::Buffer subtable(data, length);
// Check the header.
uint16_t part_count = 0;
if (!ParseMathValueRecord(file, &subtable, data, length) ||
!subtable.ReadU16(&part_count)) {
return OTS_FAILURE();
}
const unsigned sequence_end = kMathValueRecordSize +
static_cast<unsigned>(2) + part_count * kGlyphPartRecordSize;
if (sequence_end > std::numeric_limits<uint16_t>::max()) {
return OTS_FAILURE();
}
// Check the sequence of GlyphPartRecord.
for (unsigned i = 0; i < part_count; ++i) {
uint16_t glyph = 0;
uint16_t part_flags = 0;
if (!subtable.ReadU16(&glyph) ||
!subtable.Skip(2 * 3) ||
!subtable.ReadU16(&part_flags)) {
return OTS_FAILURE();
}
if (glyph >= num_glyphs) {
OTS_WARNING("bad glyph ID: %u", glyph);
return OTS_FAILURE();
}
if (part_flags & ~0x00000001) {
OTS_WARNING("unknown part flag: %u", part_flags);
return OTS_FAILURE();
}
}
return true;
}
bool ParseMathGlyphConstructionTable(const ots::OpenTypeFile *file,
const uint8_t *data,
size_t length, const uint16_t num_glyphs) {
ots::Buffer subtable(data, length);
// Check the header.
uint16_t offset_glyph_assembly = 0;
uint16_t variant_count = 0;
if (!subtable.ReadU16(&offset_glyph_assembly) ||
!subtable.ReadU16(&variant_count)) {
return OTS_FAILURE();
}
const unsigned sequence_end = static_cast<unsigned>(2 * 2) +
variant_count * 2 * 2;
if (sequence_end > std::numeric_limits<uint16_t>::max()) {
return OTS_FAILURE();
}
// Check the GlyphAssembly offset.
if (offset_glyph_assembly) {
if (offset_glyph_assembly >= length ||
offset_glyph_assembly < sequence_end) {
return OTS_FAILURE();
}
if (!ParseGlyphAssemblyTable(file, data + offset_glyph_assembly,
length - offset_glyph_assembly, num_glyphs)) {
return OTS_FAILURE();
}
}
// Check the sequence of MathGlyphVariantRecord.
for (unsigned i = 0; i < variant_count; ++i) {
uint16_t glyph = 0;
if (!subtable.ReadU16(&glyph) ||
!subtable.Skip(2)) {
return OTS_FAILURE();
}
if (glyph >= num_glyphs) {
OTS_WARNING("bad glyph ID: %u", glyph);
return OTS_FAILURE();
}
}
return true;
}
bool ParseMathGlyphConstructionSequence(const ots::OpenTypeFile *file,
ots::Buffer* subtable,
const uint8_t *data,
size_t length,
const uint16_t num_glyphs,
uint16_t offset_coverage,
uint16_t glyph_count,
const unsigned sequence_end) {
// Check coverage table.
if (offset_coverage < sequence_end || offset_coverage >= length) {
return OTS_FAILURE();
}
if (!ots::ParseCoverageTable(file, data + offset_coverage,
length - offset_coverage,
num_glyphs, glyph_count)) {
return OTS_FAILURE();
}
// Check sequence of MathGlyphConstruction.
for (unsigned i = 0; i < glyph_count; ++i) {
uint16_t offset_glyph_construction = 0;
if (!subtable->ReadU16(&offset_glyph_construction)) {
return OTS_FAILURE();
}
if (offset_glyph_construction < sequence_end ||
offset_glyph_construction >= length ||
!ParseMathGlyphConstructionTable(file, data + offset_glyph_construction,
length - offset_glyph_construction,
num_glyphs)) {
return OTS_FAILURE();
}
}
return true;
}
bool ParseMathVariantsTable(const ots::OpenTypeFile *file,
const uint8_t *data,
size_t length, const uint16_t num_glyphs) {
ots::Buffer subtable(data, length);
// Check the header.
uint16_t offset_vert_glyph_coverage = 0;
uint16_t offset_horiz_glyph_coverage = 0;
uint16_t vert_glyph_count = 0;
uint16_t horiz_glyph_count = 0;
if (!subtable.Skip(2) || // MinConnectorOverlap
!subtable.ReadU16(&offset_vert_glyph_coverage) ||
!subtable.ReadU16(&offset_horiz_glyph_coverage) ||
!subtable.ReadU16(&vert_glyph_count) ||
!subtable.ReadU16(&horiz_glyph_count)) {
return OTS_FAILURE();
}
const unsigned sequence_end = 5 * 2 + vert_glyph_count * 2 +
horiz_glyph_count * 2;
if (sequence_end > std::numeric_limits<uint16_t>::max()) {
return OTS_FAILURE();
}
if (!ParseMathGlyphConstructionSequence(file, &subtable, data, length, num_glyphs,
offset_vert_glyph_coverage,
vert_glyph_count,
sequence_end) ||
!ParseMathGlyphConstructionSequence(file, &subtable, data, length, num_glyphs,
offset_horiz_glyph_coverage,
horiz_glyph_count,
sequence_end)) {
return OTS_FAILURE();
}
return true;
}
} // namespace
#define DROP_THIS_TABLE \
do { file->math->data = 0; file->math->length = 0; } while (0)
namespace ots {
bool ots_math_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
// Grab the number of glyphs in the file from the maxp table to check
// GlyphIDs in MATH table.
if (!file->maxp) {
return OTS_FAILURE();
}
const uint16_t num_glyphs = file->maxp->num_glyphs;
Buffer table(data, length);
OpenTypeMATH* math = new OpenTypeMATH;
file->math = math;
uint32_t version = 0;
if (!table.ReadU32(&version)) {
return OTS_FAILURE();
}
if (version != 0x00010000) {
OTS_WARNING("bad MATH version");
DROP_THIS_TABLE;
return true;
}
uint16_t offset_math_constants = 0;
uint16_t offset_math_glyph_info = 0;
uint16_t offset_math_variants = 0;
if (!table.ReadU16(&offset_math_constants) ||
!table.ReadU16(&offset_math_glyph_info) ||
!table.ReadU16(&offset_math_variants)) {
return OTS_FAILURE();
}
if (offset_math_constants >= length ||
offset_math_constants < kMathHeaderSize ||
offset_math_glyph_info >= length ||
offset_math_glyph_info < kMathHeaderSize ||
offset_math_variants >= length ||
offset_math_variants < kMathHeaderSize) {
OTS_WARNING("bad offset in MATH header");
DROP_THIS_TABLE;
return true;
}
if (!ParseMathConstantsTable(file, data + offset_math_constants,
length - offset_math_constants)) {
DROP_THIS_TABLE;
return true;
}
if (!ParseMathGlyphInfoTable(file, data + offset_math_glyph_info,
length - offset_math_glyph_info, num_glyphs)) {
DROP_THIS_TABLE;
return true;
}
if (!ParseMathVariantsTable(file, data + offset_math_variants,
length - offset_math_variants, num_glyphs)) {
DROP_THIS_TABLE;
return true;
}
math->data = data;
math->length = length;
return true;
}
bool ots_math_should_serialise(OpenTypeFile *file) {
return file->math != NULL && file->math->data != NULL;
}
bool ots_math_serialise(OTSStream *out, OpenTypeFile *file) {
if (!out->Write(file->math->data, file->math->length)) {
return OTS_FAILURE();
}
return true;
}
void ots_math_free(OpenTypeFile *file) {
delete file->math;
}
} // namespace ots

25
gfx/ots/src/math_.h Normal file
View File

@ -0,0 +1,25 @@
// Copyright (c) 2014 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_MATH_H_
#define OTS_MATH_H_
#include "ots.h"
namespace ots {
struct OpenTypeMATH {
OpenTypeMATH()
: data(NULL),
length(0) {
}
const uint8_t *data;
size_t length;
};
} // namespace ots
#endif

View File

@ -5,7 +5,9 @@
#include "maxp.h"
// maxp - Maximum Profile
// http://www.microsoft.com/opentype/otspec/maxp.htm
// http://www.microsoft.com/typography/otspec/maxp.htm
#define TABLE_NAME "maxp"
namespace ots {
@ -17,19 +19,19 @@ bool ots_maxp_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
uint32_t version = 0;
if (!table.ReadU32(&version)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read version of maxp table");
}
if (version >> 16 > 1) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad maxp version %d", version);
}
if (!table.ReadU16(&maxp->num_glyphs)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read number of glyphs from maxp table");
}
if (!maxp->num_glyphs) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad number of glyphs 0 in maxp table");
}
if (version >> 16 == 1) {
@ -47,7 +49,7 @@ bool ots_maxp_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
!table.ReadU16(&maxp->max_size_glyf_instructions) ||
!table.ReadU16(&maxp->max_c_components) ||
!table.ReadU16(&maxp->max_c_depth)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read maxp table");
}
if (maxp->max_zones == 0) {
@ -61,7 +63,7 @@ bool ots_maxp_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
}
if ((maxp->max_zones != 1) && (maxp->max_zones != 2)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad max zones %d in maxp", maxp->max_zones);
}
} else {
maxp->version_1 = false;
@ -79,7 +81,7 @@ bool ots_maxp_serialise(OTSStream *out, OpenTypeFile *file) {
if (!out->WriteU32(maxp->version_1 ? 0x00010000 : 0x00005000) ||
!out->WriteU16(maxp->num_glyphs)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write maxp version or number of glyphs");
}
if (!maxp->version_1) return true;
@ -88,7 +90,7 @@ bool ots_maxp_serialise(OTSStream *out, OpenTypeFile *file) {
!out->WriteU16(maxp->max_contours) ||
!out->WriteU16(maxp->max_c_points) ||
!out->WriteU16(maxp->max_c_contours)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write maxp");
}
if (g_transcode_hints) {
@ -99,7 +101,7 @@ bool ots_maxp_serialise(OTSStream *out, OpenTypeFile *file) {
!out->WriteU16(maxp->max_idefs) ||
!out->WriteU16(maxp->max_stack) ||
!out->WriteU16(maxp->max_size_glyf_instructions)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write more maxp");
}
} else {
if (!out->WriteU16(1) || // max zones
@ -109,13 +111,13 @@ bool ots_maxp_serialise(OTSStream *out, OpenTypeFile *file) {
!out->WriteU16(0) || // max instruction defs
!out->WriteU16(0) || // max stack elements
!out->WriteU16(0)) { // max instruction byte count
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write more maxp");
}
}
if (!out->WriteU16(maxp->max_c_components) ||
!out->WriteU16(maxp->max_c_depth)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write yet more maxp");
}
return true;

View File

@ -8,8 +8,10 @@
#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
// http://www.microsoft.com/typography/otspec/hhea.htm
// http://www.microsoft.com/typography/otspec/vhea.htm
#define TABLE_NAME "metrics" // XXX: use individual table names
namespace ots {
@ -25,7 +27,7 @@ bool ParseMetricsHeader(OpenTypeFile *file, Buffer *table,
!table->ReadS16(&header->caret_slope_rise) ||
!table->ReadS16(&header->caret_slope_run) ||
!table->ReadS16(&header->caret_offset)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read metrics header");
}
if (header->ascent < 0) {
@ -38,7 +40,7 @@ bool ParseMetricsHeader(OpenTypeFile *file, Buffer *table,
}
if (!file->head) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Missing head font table");
}
// if the font is non-slanted, caret_offset should be zero.
@ -50,33 +52,34 @@ bool ParseMetricsHeader(OpenTypeFile *file, Buffer *table,
// skip the reserved bytes
if (!table->Skip(8)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to skip reserverd bytes");
}
int16_t data_format;
if (!table->ReadS16(&data_format)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read data format");
}
if (data_format) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad data format %d", data_format);
}
if (!table->ReadU16(&header->num_metrics)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read number of metrics");
}
if (!file->maxp) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Missing maxp font table");
}
if (header->num_metrics > file->maxp->num_glyphs) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad number of metrics %d", header->num_metrics);
}
return true;
}
bool SerialiseMetricsHeader(OTSStream *out,
bool SerialiseMetricsHeader(const ots::OpenTypeFile *file,
OTSStream *out,
const OpenTypeMetricsHeader *header) {
if (!out->WriteU32(header->version) ||
!out->WriteS16(header->ascent) ||
@ -92,13 +95,14 @@ bool SerialiseMetricsHeader(OTSStream *out,
!out->WriteR64(0) || // reserved
!out->WriteS16(0) || // metric data format
!out->WriteU16(header->num_metrics)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write metrics");
}
return true;
}
bool ParseMetricsTable(Buffer *table,
bool ParseMetricsTable(const ots::OpenTypeFile *file,
Buffer *table,
const uint16_t num_glyphs,
const OpenTypeMetricsHeader *header,
OpenTypeMetricsTable *metrics) {
@ -107,10 +111,10 @@ bool ParseMetricsTable(Buffer *table,
const unsigned num_metrics = header->num_metrics;
if (num_metrics > num_glyphs) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad number of metrics %d", num_metrics);
}
if (!num_metrics) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("No metrics!");
}
const unsigned num_sbs = num_glyphs - num_metrics;
@ -119,7 +123,7 @@ bool ParseMetricsTable(Buffer *table,
uint16_t adv = 0;
int16_t sb = 0;
if (!table->ReadU16(&adv) || !table->ReadS16(&sb)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read metric %d", i);
}
// Since so many fonts don't have proper value on |adv| and |sb|,
@ -143,7 +147,7 @@ bool ParseMetricsTable(Buffer *table,
int16_t sb;
if (!table->ReadS16(&sb)) {
// Some Japanese fonts (e.g., mona.ttf) fail this test.
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read side bearing %d", i + num_metrics);
}
if (sb < header->min_sb1) {
@ -159,18 +163,19 @@ bool ParseMetricsTable(Buffer *table,
return true;
}
bool SerialiseMetricsTable(OTSStream *out,
bool SerialiseMetricsTable(const ots::OpenTypeFile *file,
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();
return OTS_FAILURE_MSG("Failed to write metric %d", i);
}
}
for (unsigned i = 0; i < metrics->sbs.size(); ++i) {
if (!out->WriteS16(metrics->sbs[i])) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write side bearing %ld", i + metrics->entries.size());
}
}

View File

@ -6,7 +6,7 @@
#define OTS_METRICS_H_
#include <new>
#include <utility> // std::pair
#include <utility>
#include <vector>
#include "ots.h"
@ -35,14 +35,17 @@ struct OpenTypeMetricsTable {
bool ParseMetricsHeader(OpenTypeFile *file, Buffer *table,
OpenTypeMetricsHeader *header);
bool SerialiseMetricsHeader(OTSStream *out,
bool SerialiseMetricsHeader(const ots::OpenTypeFile *file,
OTSStream *out,
const OpenTypeMetricsHeader *header);
bool ParseMetricsTable(Buffer *table,
bool ParseMetricsTable(const ots::OpenTypeFile *file,
Buffer *table,
const uint16_t num_glyphs,
const OpenTypeMetricsHeader *header,
OpenTypeMetricsTable *metrics);
bool SerialiseMetricsTable(OTSStream *out,
bool SerialiseMetricsTable(const ots::OpenTypeFile *file,
OTSStream *out,
const OpenTypeMetricsTable *metrics);
} // namespace ots

View File

@ -18,6 +18,7 @@ SOURCES += [
'hdmx.cc',
'kern.cc',
'ltsh.cc',
'math.cc',
'vdmx.cc',
'vorg.cc',
]
@ -29,7 +30,6 @@ UNIFIED_SOURCES += [
'cvt.cc',
'fpgm.cc',
'glyf.cc',
'graphite.cc',
'head.cc',
'hhea.cc',
'hmtx.cc',
@ -42,7 +42,6 @@ UNIFIED_SOURCES += [
'ots.cc',
'post.cc',
'prep.cc',
'svg.cc',
'vhea.cc',
'vmtx.cc',
]
@ -57,7 +56,6 @@ FINAL_LIBRARY = 'gkmedias'
DEFINES['PACKAGE_VERSION'] = '"moz"'
DEFINES['PACKAGE_BUGREPORT'] = '"http://bugzilla.mozilla.org/"'
DEFINES['NOMINMAX'] = True
DEFINES['MOZ_OTS_REPORT_ERRORS'] = True
if CONFIG['OS_TARGET'] == 'WINNT':
DEFINES['OTS_DLL'] = True

View File

@ -10,7 +10,9 @@
#include "cff.h"
// name - Naming Table
// http://www.microsoft.com/opentype/otspec/name.htm
// http://www.microsoft.com/typography/otspec/name.htm
#define TABLE_NAME "name"
namespace {
@ -64,17 +66,17 @@ bool ots_name_parse(OpenTypeFile* file, const uint8_t* data, size_t length) {
uint16_t format = 0;
if (!table.ReadU16(&format) || format > 1) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read name table format or bad format %d", format);
}
uint16_t count = 0;
if (!table.ReadU16(&count)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read name count");
}
uint16_t string_offset = 0;
if (!table.ReadU16(&string_offset) || string_offset > length) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read strings offset");
}
const char* string_base = reinterpret_cast<const char*>(data) +
string_offset;
@ -95,7 +97,7 @@ bool ots_name_parse(OpenTypeFile* file, const uint8_t* data, size_t length) {
!table.ReadU16(&rec.name_id) ||
!table.ReadU16(&name_length) ||
!table.ReadU16(&name_offset)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read name entry %d", i);
}
// check platform & encoding, discard names with unknown values
switch (rec.platform_id) {
@ -166,18 +168,18 @@ bool ots_name_parse(OpenTypeFile* file, const uint8_t* data, size_t length) {
// extended name table format with language tags
uint16_t lang_tag_count;
if (!table.ReadU16(&lang_tag_count)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read language tag count");
}
for (unsigned i = 0; i < lang_tag_count; ++i) {
uint16_t tag_length = 0;
uint16_t tag_offset = 0;
if (!table.ReadU16(&tag_length) || !table.ReadU16(&tag_offset)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Faile to read tag length or offset");
}
const unsigned tag_end = static_cast<unsigned>(string_offset) +
tag_offset + tag_length;
if (tag_end > length) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("bad end of tag %d > %ld for name entry %d", tag_end, length, i);
}
std::string tag(string_base + tag_offset, tag_length);
name->lang_tags.push_back(tag);
@ -187,7 +189,7 @@ bool ots_name_parse(OpenTypeFile* file, const uint8_t* data, size_t length) {
if (table.offset() > string_offset) {
// the string storage apparently overlapped the name/tag records;
// consider this font to be badly broken
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad table offset %ld > %d", table.offset(), string_offset);
}
// check existence of required name strings (synthesize if necessary)
@ -280,12 +282,12 @@ bool ots_name_serialise(OTSStream* out, OpenTypeFile* file) {
string_offset += 2 + lang_tag_count * 4;
}
if (string_offset > 0xffff) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad string offset %ld", string_offset);
}
if (!out->WriteU16(format) ||
!out->WriteU16(name_count) ||
!out->WriteU16(string_offset)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write name header");
}
std::string string_data;
@ -298,28 +300,28 @@ bool ots_name_serialise(OTSStream* out, OpenTypeFile* file) {
!out->WriteU16(rec.name_id) ||
!out->WriteU16(rec.text.size()) ||
!out->WriteU16(string_data.size()) ) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Faile to write name entry");
}
string_data.append(rec.text);
}
if (format == 1) {
if (!out->WriteU16(lang_tag_count)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Faile to write language tag count");
}
for (std::vector<std::string>::const_iterator tag_iter =
name->lang_tags.begin();
tag_iter != name->lang_tags.end(); tag_iter++) {
if (!out->WriteU16(tag_iter->size()) ||
!out->WriteU16(string_data.size())) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write string");
}
string_data.append(*tag_iter);
}
}
if (!out->Write(string_data.data(), string_data.size())) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Faile to write string data");
}
return true;

View File

@ -18,12 +18,12 @@ struct NameRecord {
NameRecord() {
}
NameRecord(uint16_t platform_id, uint16_t encoding_id,
uint16_t language_id, uint16_t name_id)
: platform_id(platform_id),
encoding_id(encoding_id),
language_id(language_id),
name_id(name_id) {
NameRecord(uint16_t platformID, uint16_t encodingID,
uint16_t languageID, uint16_t nameID)
: platform_id(platformID),
encoding_id(encodingID),
language_id(languageID),
name_id(nameID) {
}
uint16_t platform_id;

View File

@ -7,7 +7,9 @@
#include "head.h"
// OS/2 - OS/2 and Windows Metrics
// http://www.microsoft.com/opentype/otspec/os2.htm
// http://www.microsoft.com/typography/otspec/os2.htm
#define TABLE_NAME "OS/2"
namespace ots {
@ -33,11 +35,11 @@ bool ots_os2_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
!table.ReadS16(&os2->strikeout_size) ||
!table.ReadS16(&os2->strikeout_position) ||
!table.ReadS16(&os2->family_class)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed toi read basic os2 elements");
}
if (os2->version > 4) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("os2 version too high %d", os2->version);
}
// Some linux fonts (e.g., Kedage-t.ttf and LucidaSansDemiOblique.ttf) have
@ -94,7 +96,7 @@ bool ots_os2_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
for (unsigned i = 0; i < 10; ++i) {
if (!table.ReadU8(&os2->panose[i])) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read panose in os2 table");
}
}
@ -111,7 +113,7 @@ bool ots_os2_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
!table.ReadS16(&os2->typo_linegap) ||
!table.ReadU16(&os2->win_ascent) ||
!table.ReadU16(&os2->win_descent)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read more basic os2 fields");
}
// If bit 6 is set, then bits 0 and 5 must be clear.
@ -122,7 +124,7 @@ bool ots_os2_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
// the settings of bits 0 and 1 must be reflected in the macStyle bits
// in the 'head' table.
if (!file->head) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Head table missing from font as needed by os2 table");
}
if ((os2->selection & 0x1) &&
!(file->head->mac_style & 0x2)) {
@ -146,14 +148,14 @@ bool ots_os2_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
if ((os2->version < 4) &&
(os2->selection & 0x300)) {
// bit 8 and 9 must be unset in OS/2 table versions less than 4.
return OTS_FAILURE();
return OTS_FAILURE_MSG("OS2 version %d incompatible with selection %d", os2->version, os2->selection);
}
// mask reserved bits. use only 0..9 bits.
os2->selection &= 0x3ff;
if (os2->first_char_index > os2->last_char_index) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("first char index %d > last char index %d in os2", os2->first_char_index, os2->last_char_index);
}
if (os2->typo_linegap < 0) {
OTS_WARNING("bad linegap: %d", os2->typo_linegap);
@ -175,7 +177,7 @@ bool ots_os2_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
if (!table.ReadU32(&os2->code_page_range_1) ||
!table.ReadU32(&os2->code_page_range_2)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read codepage ranges");
}
if (os2->version < 2) {
@ -196,7 +198,7 @@ bool ots_os2_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
!table.ReadU16(&os2->default_char) ||
!table.ReadU16(&os2->break_char) ||
!table.ReadU16(&os2->max_context)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read os2 version 2 information");
}
if (os2->x_height < 0) {
@ -234,12 +236,12 @@ bool ots_os2_serialise(OTSStream *out, OpenTypeFile *file) {
!out->WriteS16(os2->strikeout_size) ||
!out->WriteS16(os2->strikeout_position) ||
!out->WriteS16(os2->family_class)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write basic OS2 information");
}
for (unsigned i = 0; i < 10; ++i) {
if (!out->Write(&os2->panose[i], 1)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write os2 panose information");
}
}
@ -256,7 +258,7 @@ bool ots_os2_serialise(OTSStream *out, OpenTypeFile *file) {
!out->WriteS16(os2->typo_linegap) ||
!out->WriteU16(os2->win_ascent) ||
!out->WriteU16(os2->win_descent)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write os2 version 1 information");
}
if (os2->version < 1) {
@ -265,7 +267,7 @@ bool ots_os2_serialise(OTSStream *out, OpenTypeFile *file) {
if (!out->WriteU32(os2->code_page_range_1) ||
!out->WriteU32(os2->code_page_range_2)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write codepage ranges");
}
if (os2->version < 2) {
@ -277,7 +279,7 @@ bool ots_os2_serialise(OTSStream *out, OpenTypeFile *file) {
!out->WriteU16(os2->default_char) ||
!out->WriteU16(os2->break_char) ||
!out->WriteU16(os2->max_context)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write os2 version 2 information");
}
return true;

View File

@ -14,26 +14,30 @@
#include <map>
#include <vector>
#ifdef MOZ_OTS_WOFF2
#include "woff2.h"
#endif
// The OpenType Font File
// http://www.microsoft.com/typography/otspec/cmap.htm
namespace {
bool g_debug_output = true;
#ifdef MOZ_OTS_WOFF2
bool g_enable_woff2 = false;
#endif
#ifdef MOZ_OTS_REPORT_ERRORS
ots::MessageFunc g_message_func = NULL;
void *g_message_user_data = NULL;
ots::TableActionFunc g_table_action_func = NULL;
void *g_table_action_user_data = NULL;
// Generate a message with or without a table tag, when 'header' is the OpenTypeFile pointer
#define OTS_FAILURE_MSG_TAG(msg_,tag_) OTS_FAILURE_MSG_TAG_(header, msg_, tag_)
#define OTS_FAILURE_MSG_HDR(msg_) OTS_FAILURE_MSG_(header, msg_)
#else
#define OTS_FAILURE_MSG_TAG(msg_,tag_) OTS_FAILURE()
#define OTS_FAILURE_MSG_HDR(msg_) OTS_FAILURE()
#endif
struct OpenTypeTable {
uint32_t tag;
@ -43,15 +47,6 @@ struct OpenTypeTable {
uint32_t uncompressed_length;
};
// Round a value up to the nearest multiple of 4. Don't round the value in the
// case that rounding up overflows.
template<typename T> T Round4(T value) {
if (std::numeric_limits<T>::max() - value < 3) {
return value;
}
return (value + 3) & ~3;
}
bool CheckTag(uint32_t tag_value) {
for (unsigned i = 0; i < 4; ++i) {
const uint32_t check = tag_value & 0xff;
@ -161,33 +156,12 @@ const struct {
ots::ots_vhea_should_serialise, ots::ots_vhea_free, false },
{ "vmtx", ots::ots_vmtx_parse, ots::ots_vmtx_serialise,
ots::ots_vmtx_should_serialise, ots::ots_vmtx_free, false },
// SILGraphite layout tables - not actually parsed, just copied
{ "Silf", ots::ots_silf_parse, ots::ots_silf_serialise,
ots::ots_silf_should_serialise, ots::ots_silf_free, false },
{ "Sill", ots::ots_sill_parse, ots::ots_sill_serialise,
ots::ots_sill_should_serialise, ots::ots_sill_free, false },
{ "Gloc", ots::ots_gloc_parse, ots::ots_gloc_serialise,
ots::ots_gloc_should_serialise, ots::ots_gloc_free, false },
{ "Glat", ots::ots_glat_parse, ots::ots_glat_serialise,
ots::ots_glat_should_serialise, ots::ots_glat_free, false },
{ "Feat", ots::ots_feat_parse, ots::ots_feat_serialise,
ots::ots_feat_should_serialise, ots::ots_feat_free, false },
// SVG glyph table
{ "SVG ", ots::ots_svg_parse, ots::ots_svg_serialise,
ots::ots_svg_should_serialise, ots::ots_svg_free, false},
{ "MATH", ots::ots_math_parse, ots::ots_math_serialise,
ots::ots_math_should_serialise, ots::ots_math_free, false },
// TODO(bashi): Support mort, base, and jstf tables.
{ 0, NULL, NULL, NULL, NULL, false },
};
bool IsValidVersionTag(uint32_t tag) {
return tag == Tag("\x00\x01\x00\x00") ||
// OpenType fonts with CFF data have 'OTTO' tag.
tag == Tag("OTTO") ||
// Older Mac fonts might have 'true' or 'typ1' tag.
tag == Tag("true") ||
tag == Tag("typ1");
}
bool ProcessGeneric(ots::OpenTypeFile *header,
uint32_t signature,
ots::OTSStream *output,
@ -207,7 +181,7 @@ bool ProcessTTF(ots::OpenTypeFile *header,
if (!file.ReadTag(&header->version)) {
return OTS_FAILURE_MSG_HDR("error reading version tag");
}
if (!IsValidVersionTag(header->version)) {
if (!ots::IsValidVersionTag(header->version)) {
return OTS_FAILURE_MSG_HDR("invalid version tag");
}
@ -293,7 +267,7 @@ bool ProcessWOFF(ots::OpenTypeFile *header,
if (!file.ReadTag(&header->version)) {
return OTS_FAILURE_MSG_HDR("error reading version tag");
}
if (!IsValidVersionTag(header->version)) {
if (!ots::IsValidVersionTag(header->version)) {
return OTS_FAILURE_MSG_HDR("invalid version tag");
}
@ -371,7 +345,7 @@ bool ProcessWOFF(ots::OpenTypeFile *header,
return OTS_FAILURE_MSG_HDR("error reading table directory");
}
total_sfnt_size += Round4(table.uncompressed_length);
total_sfnt_size += ots::Round4(table.uncompressed_length);
if (total_sfnt_size > std::numeric_limits<uint32_t>::max()) {
return OTS_FAILURE_MSG_HDR("sfnt size overflow");
}
@ -387,7 +361,7 @@ bool ProcessWOFF(ots::OpenTypeFile *header,
}
// Table data must follow immediately after the header.
if (tables[first_index].offset != Round4(file.offset())) {
if (tables[first_index].offset != ots::Round4(file.offset())) {
return OTS_FAILURE_MSG_HDR("junk before tables in WOFF file");
}
@ -397,7 +371,7 @@ bool ProcessWOFF(ots::OpenTypeFile *header,
}
// Blocks must follow immediately after the previous block.
// (Except for padding with a maximum of three null bytes)
uint64_t block_end = Round4(
uint64_t block_end = ots::Round4(
static_cast<uint64_t>(tables[last_index].offset) +
static_cast<uint64_t>(tables[last_index].length));
if (block_end > std::numeric_limits<uint32_t>::max()) {
@ -407,8 +381,8 @@ bool ProcessWOFF(ots::OpenTypeFile *header,
if (block_end != meta_offset) {
return OTS_FAILURE_MSG_HDR("invalid metadata block location");
}
block_end = Round4(static_cast<uint64_t>(meta_offset) +
static_cast<uint64_t>(meta_length));
block_end = ots::Round4(static_cast<uint64_t>(meta_offset) +
static_cast<uint64_t>(meta_length));
if (block_end > std::numeric_limits<uint32_t>::max()) {
return OTS_FAILURE_MSG_HDR("invalid metadata block size");
}
@ -417,19 +391,88 @@ bool ProcessWOFF(ots::OpenTypeFile *header,
if (block_end != priv_offset) {
return OTS_FAILURE_MSG_HDR("invalid private block location");
}
block_end = Round4(static_cast<uint64_t>(priv_offset) +
static_cast<uint64_t>(priv_length));
block_end = ots::Round4(static_cast<uint64_t>(priv_offset) +
static_cast<uint64_t>(priv_length));
if (block_end > std::numeric_limits<uint32_t>::max()) {
return OTS_FAILURE_MSG_HDR("invalid private block size");
}
}
if (block_end != Round4(length)) {
if (block_end != ots::Round4(length)) {
return OTS_FAILURE_MSG_HDR("file length mismatch (trailing junk?)");
}
return ProcessGeneric(header, woff_tag, output, data, length, tables, file);
}
#ifdef MOZ_OTS_WOFF2
bool ProcessWOFF2(ots::OpenTypeFile *header,
ots::OTSStream *output, const uint8_t *data, size_t length) {
size_t decompressed_size = ots::ComputeWOFF2FinalSize(data, length);
if (decompressed_size == 0) {
return OTS_FAILURE();
}
// decompressed font must be <= 30MB
if (decompressed_size > 30 * 1024 * 1024) {
return OTS_FAILURE();
}
std::vector<uint8_t> decompressed_buffer(decompressed_size);
if (!ots::ConvertWOFF2ToTTF(&decompressed_buffer[0], decompressed_size,
data, length)) {
return OTS_FAILURE();
}
return ProcessTTF(header, output, &decompressed_buffer[0], decompressed_size);
}
#endif
ots::TableAction GetTableAction(uint32_t tag) {
ots::TableAction action = ots::TABLE_ACTION_DEFAULT;
if (g_table_action_func != NULL) {
action = g_table_action_func(htonl(tag), g_table_action_user_data);
}
if (action == ots::TABLE_ACTION_DEFAULT) {
action = ots::TABLE_ACTION_DROP;
for (unsigned i = 0; ; ++i) {
if (table_parsers[i].parse == NULL) break;
if (Tag(table_parsers[i].tag) == tag) {
action = ots::TABLE_ACTION_SANITIZE;
break;
}
}
}
assert(action != ots::TABLE_ACTION_DEFAULT); // Should never return this.
return action;
}
bool GetTableData(const uint8_t *data,
const OpenTypeTable table,
Arena *arena,
size_t *table_length,
const uint8_t **table_data) {
if (table.uncompressed_length != table.length) {
// Compressed table. Need to uncompress into memory first.
*table_length = table.uncompressed_length;
*table_data = (*arena).Allocate(*table_length);
uLongf dest_len = *table_length;
int r = uncompress((Bytef*) *table_data, &dest_len,
data + table.offset, table.length);
if (r != Z_OK || dest_len != *table_length) {
return false;
}
} else {
// Uncompressed table. We can process directly from memory.
*table_data = data + table.offset;
*table_length = table.length;
}
return true;
}
bool ProcessGeneric(ots::OpenTypeFile *header, uint32_t signature,
ots::OTSStream *output,
const uint8_t *data, size_t length,
@ -495,7 +538,7 @@ bool ProcessGeneric(ots::OpenTypeFile *header, uint32_t signature,
uint32_t end_byte = tables[i].offset + tables[i].length;
// Tables in the WOFF file must be aligned 4-byte boundary.
if (signature == Tag("wOFF")) {
end_byte = Round4(end_byte);
end_byte = ots::Round4(end_byte);
}
if (!end_byte || end_byte > length) {
return OTS_FAILURE_MSG_TAG("table overruns end of file", &tables[i].tag);
@ -538,8 +581,9 @@ bool ProcessGeneric(ots::OpenTypeFile *header, uint32_t signature,
const std::map<uint32_t, OpenTypeTable>::const_iterator it
= table_map.find(Tag(table_parsers[i].tag));
ots::TableAction action = GetTableAction(it->first);
if (it == table_map.end()) {
if (table_parsers[i].required) {
if (table_parsers[i].required && action == ots::TABLE_ACTION_SANITIZE) {
return OTS_FAILURE_MSG_TAG("missing required table", table_parsers[i].tag);
}
continue;
@ -548,23 +592,12 @@ bool ProcessGeneric(ots::OpenTypeFile *header, uint32_t signature,
const uint8_t* table_data;
size_t table_length;
if (it->second.uncompressed_length != it->second.length) {
// compressed table. Need to uncompress into memory first.
table_length = it->second.uncompressed_length;
table_data = arena.Allocate(table_length);
uLongf dest_len = table_length;
int r = uncompress((Bytef*) table_data, &dest_len,
data + it->second.offset, it->second.length);
if (r != Z_OK || dest_len != table_length) {
return OTS_FAILURE_MSG_TAG("uncompress failed", table_parsers[i].tag);
}
} else {
// uncompressed table. We can process directly from memory.
table_data = data + it->second.offset;
table_length = it->second.length;
if (!GetTableData(data, it->second, &arena, &table_length, &table_data)) {
return OTS_FAILURE_MSG_TAG("uncompress failed", table_parsers[i].tag);
}
if (!table_parsers[i].parse(header, table_data, table_length)) {
if (action == ots::TABLE_ACTION_SANITIZE &&
!table_parsers[i].parse(header, table_data, table_length)) {
// TODO: parsers should generate specific messages detailing the failure;
// once those are all added, we won't need a generic failure message here
return OTS_FAILURE_MSG_TAG("failed to parse table", table_parsers[i].tag);
@ -599,6 +632,14 @@ bool ProcessGeneric(ots::OpenTypeFile *header, uint32_t signature,
}
}
for (std::map<uint32_t, OpenTypeTable>::const_iterator it = table_map.begin();
it != table_map.end(); ++it) {
ots::TableAction action = GetTableAction(it->first);
if (action == ots::TABLE_ACTION_PASSTHRU) {
num_output_tables++;
}
}
unsigned max_pow2 = 0;
while (1u << (max_pow2 + 1) <= num_output_tables) {
max_pow2++;
@ -663,6 +704,47 @@ bool ProcessGeneric(ots::OpenTypeFile *header, uint32_t signature,
out_tables.push_back(out);
}
for (std::map<uint32_t, OpenTypeTable>::const_iterator it = table_map.begin();
it != table_map.end(); ++it) {
ots::TableAction action = GetTableAction(it->first);
if (action == ots::TABLE_ACTION_PASSTHRU) {
OutputTable out;
out.tag = it->second.tag;
out.offset = output->Tell();
output->ResetChecksum();
if (it->second.tag == Tag("head")) {
head_table_offset = out.offset;
}
const uint8_t* table_data;
size_t table_length;
if (!GetTableData(data, it->second, &arena, &table_length, &table_data)) {
return OTS_FAILURE_MSG_HDR("Failed to uncompress table");
}
if (!output->Write(table_data, table_length)) {
return OTS_FAILURE_MSG_HDR("Failed to serialize table");
}
const size_t end_offset = output->Tell();
if (end_offset <= out.offset) {
// paranoid check. |end_offset| is supposed to be greater than the offset,
// as long as the Tell() interface is implemented correctly.
return OTS_FAILURE_MSG_HDR("error writing output");
}
out.length = end_offset - out.offset;
// align tables to four bytes
if (!output->Pad((4 - (end_offset & 3)) % 4)) {
return OTS_FAILURE_MSG_HDR("error writing output");
}
out.chksum = output->chksum();
out_tables.push_back(out);
}
}
const size_t end_of_file = output->Tell();
// Need to sort the output tables for inclusion in the file
@ -711,31 +793,54 @@ bool ProcessGeneric(ots::OpenTypeFile *header, uint32_t signature,
namespace ots {
bool IsValidVersionTag(uint32_t tag) {
return tag == Tag("\x00\x01\x00\x00") ||
// OpenType fonts with CFF data have 'OTTO' tag.
tag == Tag("OTTO") ||
// Older Mac fonts might have 'true' or 'typ1' tag.
tag == Tag("true") ||
tag == Tag("typ1");
}
void DisableDebugOutput() {
g_debug_output = false;
}
bool OTS_API Process(OTSStream *output, const uint8_t *data, size_t length,
#ifdef MOZ_OTS_REPORT_ERRORS
MessageFunc message_func, void *user_data,
#ifdef MOZ_OTS_WOFF2
void EnableWOFF2() {
g_enable_woff2 = true;
}
#endif
bool preserveGraphite) {
void SetMessageCallback(MessageFunc func, void *user_data) {
g_message_func = func;
g_message_user_data = user_data;
}
void SetTableActionCallback(TableActionFunc func, void *user_data) {
g_table_action_func = func;
g_table_action_user_data = user_data;
}
bool Process(OTSStream *output, const uint8_t *data, size_t length) {
OpenTypeFile header;
#ifdef MOZ_OTS_REPORT_ERRORS
header.message_func = message_func;
header.user_data = user_data;
#endif
header.message_func = g_message_func;
header.user_data = g_message_user_data;
if (length < 4) {
return OTS_FAILURE_MSG_(&header, "file less than 4 bytes");
}
header.preserve_graphite = preserveGraphite;
bool result;
if (data[0] == 'w' && data[1] == 'O' && data[2] == 'F' && data[3] == 'F') {
result = ProcessWOFF(&header, output, data, length);
#ifdef MOZ_OTS_WOFF2
} else if (g_enable_woff2 &&
data[0] == 'w' && data[1] == 'O' && data[2] == 'F' &&
data[3] == '2') {
result = ProcessWOFF2(&header, output, data, length);
#endif
} else {
result = ProcessTTF(&header, output, data, length);
}

View File

@ -11,9 +11,15 @@
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <limits>
#include "opentype-sanitiser.h"
// arraysize borrowed from base/basictypes.h
template <typename T, size_t N>
char (&ArraySizeHelper(T (&array)[N]))[N];
#define arraysize(array) (sizeof(ArraySizeHelper(array)))
namespace ots {
#if defined(_MSC_VER) || !defined(OTS_DEBUG)
@ -38,39 +44,28 @@ void Warning(const char *f, int l, const char *format, ...)
#endif
#endif
#ifdef MOZ_OTS_REPORT_ERRORS
// All OTS_FAILURE_* macros ultimately evaluate to 'false', just like the original
// message-less OTS_FAILURE(), so that the current parser will return 'false' as
// its result (indicating a failure).
// If the message-callback feature is enabled, and a message_func pointer has been
// provided, this will be called before returning the 'false' status.
// If a message_func pointer has been provided, this will be called before returning
// the 'false' status.
// Generate a simple message
#define OTS_FAILURE_MSG_(otf_,msg_) \
#define OTS_FAILURE_MSG_(otf_,...) \
((otf_)->message_func && \
(*(otf_)->message_func)((otf_)->user_data, "%s", msg_) && \
(*(otf_)->message_func)((otf_)->user_data, __VA_ARGS__) && \
false)
// Generate a message with an associated table tag
#define OTS_FAILURE_MSG_TAG_(otf_,msg_,tag_) \
((otf_)->message_func && \
(*(otf_)->message_func)((otf_)->user_data, "table '%4.4s': %s", tag_, msg_) && \
(*(otf_)->message_func)((otf_)->user_data, "%4.4s: %s", tag_, msg_) && \
false)
// Convenience macro for use in files that only handle a single table tag,
// defined as TABLE_NAME at the top of the file; the 'file' variable is
// expected to be the current OpenTypeFile pointer.
#define OTS_FAILURE_MSG(msg_) OTS_FAILURE_MSG_TAG_(file, msg_, TABLE_NAME)
#else
// If the message-callback feature is not enabled, error messages are just dropped.
#define OTS_FAILURE_MSG_(otf_,msg_) OTS_FAILURE()
#define OTS_FAILURE_MSG_TAG_(otf_,msg_,tag_) OTS_FAILURE()
#define OTS_FAILURE_MSG(msg_) OTS_FAILURE()
#endif
#define OTS_FAILURE_MSG(...) OTS_FAILURE_MSG_(file, TABLE_NAME ": " __VA_ARGS__)
// Define OTS_NO_TRANSCODE_HINTS (i.e., g++ -DOTS_NO_TRANSCODE_HINTS) if you
// want to omit TrueType hinting instructions and variables in glyf, fpgm, prep,
@ -90,8 +85,8 @@ const bool g_transcode_hints = true;
// -----------------------------------------------------------------------------
class Buffer {
public:
Buffer(const uint8_t *buffer, size_t len)
: buffer_(buffer),
Buffer(const uint8_t *buf, size_t len)
: buffer_(buf),
length_(len),
offset_(0) { }
@ -99,7 +94,7 @@ class Buffer {
return Read(NULL, n_bytes);
}
bool Read(uint8_t *buffer, size_t n_bytes) {
bool Read(uint8_t *buf, size_t n_bytes) {
if (n_bytes > 1024 * 1024 * 1024) {
return OTS_FAILURE();
}
@ -107,8 +102,8 @@ class Buffer {
(offset_ > length_ - n_bytes)) {
return OTS_FAILURE();
}
if (buffer) {
std::memcpy(buffer, buffer_ + offset_, n_bytes);
if (buf) {
std::memcpy(buf, buffer_ + offset_, n_bytes);
}
offset_ += n_bytes;
return true;
@ -192,6 +187,24 @@ class Buffer {
size_t offset_;
};
// Round a value up to the nearest multiple of 4. Don't round the value in the
// case that rounding up overflows.
template<typename T> T Round4(T value) {
if (std::numeric_limits<T>::max() - value < 3) {
return value;
}
return (value + 3) & ~3;
}
template<typename T> T Round2(T value) {
if (value == std::numeric_limits<T>::max()) {
return value;
}
return (value + 1) & ~1;
}
bool IsValidVersionTag(uint32_t tag);
#define FOR_EACH_TABLE_TYPE \
F(cff, CFF) \
F(cmap, CMAP) \
@ -209,6 +222,7 @@ class Buffer {
F(kern, KERN) \
F(loca, LOCA) \
F(ltsh, LTSH) \
F(math, MATH) \
F(maxp, MAXP) \
F(name, NAME) \
F(os2, OS2) \
@ -217,13 +231,7 @@ class Buffer {
F(vdmx, VDMX) \
F(vorg, VORG) \
F(vhea, VHEA) \
F(vmtx, VMTX) \
F(silf, SILF) \
F(sill, SILL) \
F(glat, GLAT) \
F(gloc, GLOC) \
F(feat, FEAT) \
F(svg, SVG)
F(vmtx, VMTX)
#define F(name, capname) struct OpenType##capname;
FOR_EACH_TABLE_TYPE
@ -242,14 +250,8 @@ struct OpenTypeFile {
uint16_t entry_selector;
uint16_t range_shift;
#ifdef MOZ_OTS_REPORT_ERRORS
MessageFunc message_func;
void *user_data;
#endif
// This is used to tell the relevant parsers whether to preserve the
// Graphite layout tables (currently _without_ any checking)
bool preserve_graphite;
#define F(name, capname) OpenType##capname *name;
FOR_EACH_TABLE_TYPE

View File

@ -7,7 +7,9 @@
#include "maxp.h"
// post - PostScript
// http://www.microsoft.com/opentype/otspec/post.htm
// http://www.microsoft.com/typography/otspec/post.htm
#define TABLE_NAME "post"
namespace ots {
@ -22,7 +24,7 @@ bool ots_post_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
!table.ReadS16(&post->underline) ||
!table.ReadS16(&post->underline_thickness) ||
!table.ReadU32(&post->is_fixed_pitch)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read post header");
}
if (post->underline_thickness < 0) {
@ -35,7 +37,7 @@ bool ots_post_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
return true;
} else if (post->version != 0x00020000) {
// 0x00025000 is deprecated. We don't accept it.
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad post version %x", post->version);
}
// We have a version 2 table with a list of Pascal strings at the end
@ -43,21 +45,21 @@ bool ots_post_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
// We don't care about the memory usage fields. We'll set all these to zero
// when serialising
if (!table.Skip(16)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to skip memory usage in post table");
}
uint16_t num_glyphs = 0;
if (!table.ReadU16(&num_glyphs)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read number of glyphs");
}
if (!file->maxp) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("No maxp table required by post table");
}
if (num_glyphs == 0) {
if (file->maxp->num_glyphs > 258) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Can't have no glyphs in the post table if there are more than 256 glyphs in the font");
}
OTS_WARNING("table version is 1, but no glyf names are found");
// workaround for fonts in http://www.fontsquirrel.com/fontface
@ -68,18 +70,17 @@ bool ots_post_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
if (num_glyphs != file->maxp->num_glyphs) {
// Note: Fixedsys500c.ttf seems to have inconsistent num_glyphs values.
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad number of glyphs in post table %d", num_glyphs);
}
post->glyph_name_index.resize(num_glyphs);
for (unsigned i = 0; i < num_glyphs; ++i) {
if (!table.ReadU16(&post->glyph_name_index[i])) {
return OTS_FAILURE();
}
if (post->glyph_name_index[i] >= 32768) {
// Note: droid_arialuni.ttf fails this test.
return OTS_FAILURE(); // reserved area.
return OTS_FAILURE_MSG("Failed to read post information for glyph %d", i);
}
// Note: A strict interpretation of the specification requires name indexes
// are less than 32768. This, however, excludes fonts like unifont.ttf
// which cover all of unicode.
}
// Now we have an array of Pascal strings. We have to check that they are all
@ -92,10 +93,10 @@ bool ots_post_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
if (strings == strings_end) break;
const unsigned string_length = *strings;
if (strings + 1 + string_length > strings_end) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad string length %d", string_length);
}
if (std::memchr(strings + 1, '\0', string_length)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad string of length %d", string_length);
}
post->names.push_back(
std::string(reinterpret_cast<const char*>(strings + 1), string_length));
@ -112,7 +113,7 @@ bool ots_post_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
offset -= 258;
if (offset >= num_strings) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad string index %d", offset);
}
}
@ -128,7 +129,7 @@ bool ots_post_serialise(OTSStream *out, OpenTypeFile *file) {
// OpenType with CFF glyphs must have v3 post table.
if (file->post && file->cff && file->post->version != 0x00030000) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad post version %x", post->version);
}
if (!out->WriteU32(post->version) ||
@ -140,7 +141,7 @@ bool ots_post_serialise(OTSStream *out, OpenTypeFile *file) {
!out->WriteU32(0) ||
!out->WriteU32(0) ||
!out->WriteU32(0)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write post header");
}
if (post->version != 0x00020000) {
@ -148,12 +149,12 @@ bool ots_post_serialise(OTSStream *out, OpenTypeFile *file) {
}
if (!out->WriteU16(post->glyph_name_index.size())) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write number of indices");
}
for (unsigned i = 0; i < post->glyph_name_index.size(); ++i) {
if (!out->WriteU16(post->glyph_name_index[i])) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write name index %d", i);
}
}
@ -162,12 +163,12 @@ bool ots_post_serialise(OTSStream *out, OpenTypeFile *file) {
const std::string& s = post->names[i];
const uint8_t string_length = s.size();
if (!out->Write(&string_length, 1)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write string %d", i);
}
// Some ttf fonts (e.g., frank.ttf on Windows Vista) have zero-length name.
// We allow them.
if (string_length > 0 && !out->Write(s.data(), string_length)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write string length for string %d", i);
}
}

View File

@ -5,7 +5,9 @@
#include "prep.h"
// prep - Control Value Program
// http://www.microsoft.com/opentype/otspec/prep.htm
// http://www.microsoft.com/typography/otspec/prep.htm
#define TABLE_NAME "prep"
namespace ots {
@ -16,11 +18,11 @@ bool ots_prep_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
file->prep = prep;
if (length >= 128 * 1024u) {
return OTS_FAILURE(); // almost all prep tables are less than 9k bytes.
return OTS_FAILURE_MSG("table length %ld > 120K", length); // almost all prep tables are less than 9k bytes.
}
if (!table.Skip(length)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read table of length %ld", length);
}
prep->data = data;
@ -37,7 +39,7 @@ bool ots_prep_serialise(OTSStream *out, OpenTypeFile *file) {
const OpenTypePREP *prep = file->prep;
if (!out->Write(prep->data, prep->length)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write table length");
}
return true;

View File

@ -1,115 +0,0 @@
// Copyright (c) 2012 Mozilla Foundation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ots.h"
#include "svg.h"
#define NONFATAL_FAILURE(msg) \
do { \
OTS_WARNING(msg); \
delete file->svg; file->svg = 0; \
return true; \
} while (0)
namespace ots {
bool ots_svg_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
Buffer table(data, length);
OpenTypeSVG *svg = new OpenTypeSVG;
file->svg = svg;
uint16_t version;
if (!table.ReadU16(&version)) {
NONFATAL_FAILURE("Couldn't read SVG table header");
}
if (version != 0) {
NONFATAL_FAILURE("Unknown SVG table version");
}
uint32_t doc_index_offset;
if (!table.ReadU32(&doc_index_offset)) {
NONFATAL_FAILURE("Couldn't read doc index offset from SVG table header");
}
if (doc_index_offset == 0 || doc_index_offset >= length) {
NONFATAL_FAILURE("Invalid doc index offset");
}
uint32_t color_palettes_offset;
if (!table.ReadU32(&color_palettes_offset)) {
NONFATAL_FAILURE("Couldn't read color palettes offset from SVG table header");
}
if (color_palettes_offset >= length) {
NONFATAL_FAILURE("Invalid doc index offset");
}
uint16_t start_glyph;
uint16_t end_glyph;
uint32_t doc_offset;
uint32_t doc_length;
uint16_t last_end_glyph = 0;
table.set_offset(doc_index_offset);
uint16_t index_length;
if (!table.ReadU16(&index_length)) {
NONFATAL_FAILURE("Couldn't read SVG documents index");
}
if (index_length == 0) {
NONFATAL_FAILURE("Zero-length documents index");
}
for (uint16_t i = 0; i < index_length; i++) {
if (!table.ReadU16(&start_glyph) ||
!table.ReadU16(&end_glyph) ||
!table.ReadU32(&doc_offset) ||
!table.ReadU32(&doc_length)) {
NONFATAL_FAILURE("Couldn't read SVG table index");
}
if (end_glyph < start_glyph) {
NONFATAL_FAILURE("Bad SVG table index range");
}
if (last_end_glyph && start_glyph <= last_end_glyph) {
NONFATAL_FAILURE("SVG table index range overlapping or not sorted");
}
if (doc_offset > 1024 * 1024 * 1024 ||
doc_length > 1024 * 1024 * 1024) {
NONFATAL_FAILURE("Bad SVG document length");
}
if (uint64_t(doc_index_offset) + doc_offset + doc_length > length) {
NONFATAL_FAILURE("SVG table document overflows table");
}
last_end_glyph = end_glyph;
}
svg->data = data;
svg->length = length;
return true;
}
bool ots_svg_serialise(OTSStream *out, OpenTypeFile *file) {
OpenTypeSVG *svg = file->svg;
if (!out->Write(svg->data, svg->length)) {
return OTS_FAILURE();
}
return true;
}
bool ots_svg_should_serialise(OpenTypeFile *file) {
return file->svg;
}
void ots_svg_free(OpenTypeFile *file) {
delete file->svg;
}
}

View File

@ -1,21 +0,0 @@
// Copyright (c) 2012 Mozilla Foundation. 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_SVG_H
#define OTS_SVG_H
#include <map>
#include "ots.h"
namespace ots {
struct OpenTypeSVG {
const uint8_t *data;
size_t length;
};
}
#endif

View File

@ -5,10 +5,16 @@
#include "vdmx.h"
// VDMX - Vertical Device Metrics
// http://www.microsoft.com/opentype/otspec/vdmx.htm
// http://www.microsoft.com/typography/otspec/vdmx.htm
#define TABLE_NAME "VDMX"
#define DROP_THIS_TABLE \
do { delete file->vdmx; file->vdmx = 0; } while (0)
do { \
delete file->vdmx; \
file->vdmx = 0; \
OTS_FAILURE_MSG("Table discarded"); \
} while (0)
namespace ots {
@ -20,7 +26,7 @@ bool ots_vdmx_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
if (!table.ReadU16(&vdmx->version) ||
!table.ReadU16(&vdmx->num_recs) ||
!table.ReadU16(&vdmx->num_ratios)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read table header");
}
if (vdmx->version > 1) {
@ -37,7 +43,7 @@ bool ots_vdmx_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
!table.ReadU8(&rec.x_ratio) ||
!table.ReadU8(&rec.y_start_ratio) ||
!table.ReadU8(&rec.y_end_ratio)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read ratio header %d", i);
}
if (rec.charset > 1) {
@ -73,10 +79,10 @@ bool ots_vdmx_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
for (unsigned i = 0; i < vdmx->num_ratios; ++i) {
uint16_t offset;
if (!table.ReadU16(&offset)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read ratio offset %d", i);
}
if (current_offset + offset >= length) { // thus doesn't overflow.
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad ratio offset %d for ration %d", offset, i);
}
vdmx->offsets.push_back(offset);
@ -88,7 +94,7 @@ bool ots_vdmx_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
if (!table.ReadU16(&group.recs) ||
!table.ReadU8(&group.startsz) ||
!table.ReadU8(&group.endsz)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read record header %d", i);
}
group.entries.reserve(group.recs);
for (unsigned j = 0; j < group.recs; ++j) {
@ -96,7 +102,7 @@ bool ots_vdmx_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
if (!table.ReadU16(&vt.y_pel_height) ||
!table.ReadS16(&vt.y_max) ||
!table.ReadS16(&vt.y_min)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read reacord %d group %d", i, j);
}
if (vt.y_max < vt.y_min) {
OTS_WARNING("bad y min/max");
@ -131,7 +137,7 @@ bool ots_vdmx_serialise(OTSStream *out, OpenTypeFile *file) {
if (!out->WriteU16(vdmx->version) ||
!out->WriteU16(vdmx->num_recs) ||
!out->WriteU16(vdmx->num_ratios)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write table header");
}
for (unsigned i = 0; i < vdmx->rat_ranges.size(); ++i) {
@ -140,13 +146,13 @@ bool ots_vdmx_serialise(OTSStream *out, OpenTypeFile *file) {
!out->Write(&rec.x_ratio, 1) ||
!out->Write(&rec.y_start_ratio, 1) ||
!out->Write(&rec.y_end_ratio, 1)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write ratio %d", i);
}
}
for (unsigned i = 0; i < vdmx->offsets.size(); ++i) {
if (!out->WriteU16(vdmx->offsets[i])) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write ratio offset %d", i);
}
}
@ -155,14 +161,14 @@ bool ots_vdmx_serialise(OTSStream *out, OpenTypeFile *file) {
if (!out->WriteU16(group.recs) ||
!out->Write(&group.startsz, 1) ||
!out->Write(&group.endsz, 1)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write group %d", i);
}
for (unsigned j = 0; j < group.entries.size(); ++j) {
const OpenTypeVDMXVTable& vt = group.entries[j];
if (!out->WriteU16(vt.y_pel_height) ||
!out->WriteS16(vt.y_max) ||
!out->WriteS16(vt.y_min)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write group %d entry %d", i, j);
}
}
}

View File

@ -9,7 +9,9 @@
#include "maxp.h"
// vhea - Vertical Header Table
// http://www.microsoft.com/opentype/otspec/vhea.htm
// http://www.microsoft.com/typography/otspec/vhea.htm
#define TABLE_NAME "vhea"
namespace ots {
@ -19,15 +21,15 @@ bool ots_vhea_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
file->vhea = vhea;
if (!table.ReadU32(&vhea->header.version)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read version");
}
if (vhea->header.version != 0x00010000 &&
vhea->header.version != 0x00011000) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Bad vhea version %x", vhea->header.version);
}
if (!ParseMetricsHeader(file, &table, &vhea->header)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse metrics in vhea");
}
return true;
@ -42,8 +44,8 @@ bool ots_vhea_should_serialise(OpenTypeFile *file) {
}
bool ots_vhea_serialise(OTSStream *out, OpenTypeFile *file) {
if (!SerialiseMetricsHeader(out, &file->vhea->header)) {
return OTS_FAILURE();
if (!SerialiseMetricsHeader(file, out, &file->vhea->header)) {
return OTS_FAILURE_MSG("Failed to write vhea metrics");
}
return true;
}

View File

@ -9,7 +9,9 @@
#include "vhea.h"
// vmtx - Vertical Metrics Table
// http://www.microsoft.com/opentype/otspec/vmtx.htm
// http://www.microsoft.com/typography/otspec/vmtx.htm
#define TABLE_NAME "vmtx"
namespace ots {
@ -19,12 +21,12 @@ bool ots_vmtx_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
file->vmtx = vmtx;
if (!file->vhea || !file->maxp) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("vhea or maxp table missing as needed by vmtx");
}
if (!ParseMetricsTable(&table, file->maxp->num_glyphs,
if (!ParseMetricsTable(file, &table, file->maxp->num_glyphs,
&file->vhea->header, &vmtx->metrics)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to parse vmtx metrics");
}
return true;
@ -38,8 +40,8 @@ bool ots_vmtx_should_serialise(OpenTypeFile *file) {
}
bool ots_vmtx_serialise(OTSStream *out, OpenTypeFile *file) {
if (!SerialiseMetricsTable(out, &file->vmtx->metrics)) {
return OTS_FAILURE();
if (!SerialiseMetricsTable(file, out, &file->vmtx->metrics)) {
return OTS_FAILURE_MSG("Failed to write vmtx metrics");
}
return true;
}

View File

@ -7,10 +7,16 @@
#include <vector>
// VORG - Vertical Origin Table
// http://www.microsoft.com/opentype/otspec/vorg.htm
// http://www.microsoft.com/typography/otspec/vorg.htm
#define TABLE_NAME "VORG"
#define DROP_THIS_TABLE \
do { delete file->vorg; file->vorg = 0; } while (0)
do { \
delete file->vorg; \
file->vorg = 0; \
OTS_FAILURE_MSG("Table discarded"); \
} while (0)
namespace ots {
@ -24,7 +30,7 @@ bool ots_vorg_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
!table.ReadU16(&vorg->minor_version) ||
!table.ReadS16(&vorg->default_vert_origin_y) ||
!table.ReadU16(&num_recs)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read header");
}
if (vorg->major_version != 1) {
OTS_WARNING("bad major version: %u", vorg->major_version);
@ -49,7 +55,7 @@ bool ots_vorg_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
if (!table.ReadU16(&rec.glyph_index) ||
!table.ReadS16(&rec.vert_origin_y)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to read record %d", i);
}
if ((i != 0) && (rec.glyph_index <= last_glyph_index)) {
OTS_WARNING("the table is not sorted");
@ -76,14 +82,14 @@ bool ots_vorg_serialise(OTSStream *out, OpenTypeFile *file) {
!out->WriteU16(vorg->minor_version) ||
!out->WriteS16(vorg->default_vert_origin_y) ||
!out->WriteU16(vorg->metrics.size())) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write table header");
}
for (unsigned i = 0; i < vorg->metrics.size(); ++i) {
const OpenTypeVORGMetrics& rec = vorg->metrics[i];
if (!out->WriteU16(rec.glyph_index) ||
!out->WriteS16(rec.vert_origin_y)) {
return OTS_FAILURE();
return OTS_FAILURE_MSG("Failed to write record %d", i);
}
}

View File

@ -298,12 +298,16 @@ gfxPlatform::gfxPlatform()
mOpenTypeSVGEnabled = UNINITIALIZED_VALUE;
mBidiNumeralOption = UNINITIALIZED_VALUE;
mLayersPreferMemoryOverShmem =
XRE_GetProcessType() == GeckoProcessType_Default &&
Preferences::GetBool("layers.prefer-memory-over-shmem", true);
mLayersPreferMemoryOverShmem = XRE_GetProcessType() == GeckoProcessType_Default;
#ifdef XP_WIN
// XXX - When 957560 is fixed, the pref can go away entirely
mLayersUseDeprecated =
Preferences::GetBool("layers.use-deprecated-textures", true);
Preferences::GetBool("layers.use-deprecated-textures", true)
&& !Preferences::GetBool("layers.prefer-opengl", false);
#else
mLayersUseDeprecated = false;
#endif
Preferences::AddBoolVarCache(&mDrawLayerBorders,
"layers.draw-borders",

View File

@ -321,7 +321,21 @@ private:
off_t mOff;
};
#ifdef MOZ_OTS_REPORT_ERRORS
static ots::TableAction
OTSTableAction(uint32_t aTag, void *aUserData)
{
// preserve Graphite and SVG tables
if (aTag == TRUETYPE_TAG('S', 'i', 'l', 'f') ||
aTag == TRUETYPE_TAG('S', 'i', 'l', 'l') ||
aTag == TRUETYPE_TAG('G', 'l', 'o', 'c') ||
aTag == TRUETYPE_TAG('G', 'l', 'a', 't') ||
aTag == TRUETYPE_TAG('F', 'e', 'a', 't') ||
aTag == TRUETYPE_TAG('S', 'V', 'G', ' ')) {
return ots::TABLE_ACTION_PASSTHRU;
}
return ots::TABLE_ACTION_DEFAULT;
}
struct OTSCallbackUserData {
gfxUserFontSet *mFontSet;
gfxMixedFontFamily *mFamily;
@ -346,7 +360,6 @@ gfxUserFontSet::OTSMessage(void *aUserData, const char *format, ...)
return false;
}
#endif
// Call the OTS library to sanitize an sfnt before attempting to use it.
// Returns a newly-allocated block, or nullptr in case of fatal errors.
@ -360,19 +373,15 @@ gfxUserFontSet::SanitizeOpenTypeData(gfxMixedFontFamily *aFamily,
ExpandingMemoryStream output(aIsCompressed ? aLength * 2 : aLength,
1024 * 1024 * 256);
#ifdef MOZ_OTS_REPORT_ERRORS
OTSCallbackUserData userData;
userData.mFontSet = this;
userData.mFamily = aFamily;
userData.mProxy = aProxy;
#define ERROR_REPORTING_ARGS &gfxUserFontSet::OTSMessage, &userData,
#else
#define ERROR_REPORTING_ARGS
#endif
if (ots::Process(&output, aData, aLength,
ERROR_REPORTING_ARGS
true)) {
ots::SetTableActionCallback(&OTSTableAction, nullptr);
ots::SetMessageCallback(&gfxUserFontSet::OTSMessage, &userData);
if (ots::Process(&output, aData, aLength)) {
aSaneLength = output.Tell();
return static_cast<uint8_t*>(output.forget());
} else {

View File

@ -414,9 +414,7 @@ protected:
uint32_t& aSaneLength,
bool aIsCompressed);
#ifdef MOZ_OTS_REPORT_ERRORS
static bool OTSMessage(void *aUserData, const char *format, ...);
#endif
// font families defined by @font-face rules
nsRefPtrHashtable<nsStringHashKey, gfxMixedFontFamily> mFontFamilies;

View File

@ -303,7 +303,6 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
# top of the android java runtime.
DEFINES['MOZ_USING_ANDROID_JAVA_WIDGETS'] = True
DEFINES['MOZ_OTS_REPORT_ERRORS'] = True
DEFINES['GRAPHITE2_STATIC'] = True
if CONFIG['OS_TARGET'] == 'WINNT':

View File

@ -1,9 +1,5 @@
// |jit-test| error:InternalError
// This test is temporarily disabled in GGC builds (bug 950932).
if (getBuildConfiguration()['generational-gc'])
(function f() { f(); })();
// Binary: cache/js-dbg-64-67bf9a4a1f77-linux
// Flags: --ion-eager
//

View File

@ -0,0 +1,58 @@
function test1(re, test) {
return re.test(test);
}
assertEq(true, test1(/undefined/, undefined));
assertEq(true, test1(/undefined/, undefined));
function test2(re, test) {
return re.test(test);
}
assertEq(true, test2(/null/, null));
assertEq(true, test2(/null/, null));
function test3(re, test) {
return re.test(test);
}
assertEq(true, test3(/0/, 0));
assertEq(true, test3(/0/, 0));
function test4(re, test) {
return re.test(test);
}
assertEq(true, test4(/12.12/, 12.12));
assertEq(true, test4(/12.12/, 12.12));
function test5(re, test) {
return re.test(test);
}
assertEq(true, test5(/true/, true));
assertEq(true, test5(/false/, false));
assertEq(true, test5(/true/, true));
assertEq(true, test5(/false/, false));
function test6(re, test) {
return re.test(test);
}
assertEq(true, test6(/object/, {}));
assertEq(true, test6(/object/, {}));
assertEq(true, test1(/test/, "test"));
assertEq(true, test1(/test/, "test"));
assertEq(true, test1(/undefined/, undefined));
assertEq(true, test1(/undefined/, undefined));
assertEq(true, test1(/null/, null));
assertEq(true, test1(/null/, null));
assertEq(true, test1(/0.1/, 0.1));
assertEq(true, test1(/0.1/, 0.1));
assertEq(true, test1(/20000/, 20000));
assertEq(true, test1(/20000/, 20000));
assertEq(true, test1(/object/, {}));
assertEq(true, test1(/object/, {}));

View File

@ -0,0 +1,26 @@
a = 'a';
b = 0
var i=0;
exhaustiveSliceTest("exhaustive slice test 1", a);
var i=1;
exhaustiveSliceTest("exhaustive slice test 2", b);
exhaustiveSliceTest("exhaustive slice test 3", 0);
var i=0;
var executed = false;
try {
exhaustiveSliceTest("exhaustive slice test 4", 0);
} catch(e) {
executed = true;
}
assertEq(executed, true);
function exhaustiveSliceTest(testname, a) {
print(testname)
for (var y = 0; y < 2; y++)
{
print(a.length)
if (a.length == 2 || i == 1)
return 0;
var b = a.slice(0,0);
}
}

View File

@ -1,8 +1,3 @@
// This test is temporarily disabled in GGC builds (bug 950931).
if (getBuildConfiguration()['generational-gc'])
quit();
// The ray tracer code in this file is written by Adam Burmister. It
// is available in its original form from:
//

View File

@ -697,6 +697,36 @@ CodeGenerator::visitTypeObjectDispatch(LTypeObjectDispatch *lir)
return true;
}
bool
CodeGenerator::visitBooleanToString(LBooleanToString *lir)
{
Register input = ToRegister(lir->input());
Register output = ToRegister(lir->output());
const JSAtomState &names = GetIonContext()->runtime->names();
Label true_, done;
masm.branchTest32(Assembler::NonZero, input, input, &true_);
masm.movePtr(ImmGCPtr(names.false_), output);
masm.jump(&done);
masm.bind(&true_);
masm.movePtr(ImmGCPtr(names.true_), output);
masm.bind(&done);
return true;
}
void
CodeGenerator::emitIntToString(Register input, Register output, Label *ool)
{
masm.branch32(Assembler::AboveOrEqual, input, Imm32(StaticStrings::INT_STATIC_LIMIT), ool);
// Fast path for small integers.
masm.movePtr(ImmPtr(&GetIonContext()->runtime->staticStrings().intStaticTable), output);
masm.loadPtr(BaseIndex(output, input, ScalePointer), output);
}
typedef JSFlatString *(*IntToStringFn)(ThreadSafeContext *, int);
typedef JSFlatString *(*IntToStringParFn)(ForkJoinSlice *, int);
static const VMFunctionsModal IntToStringInfo = VMFunctionsModal(
@ -714,11 +744,7 @@ CodeGenerator::visitIntToString(LIntToString *lir)
if (!ool)
return false;
masm.branch32(Assembler::AboveOrEqual, input, Imm32(StaticStrings::INT_STATIC_LIMIT),
ool->entry());
masm.movePtr(ImmPtr(&GetIonContext()->runtime->staticStrings().intStaticTable), output);
masm.loadPtr(BaseIndex(output, input, ScalePointer), output);
emitIntToString(input, output, ool->entry());
masm.bind(ool->rejoin());
return true;
@ -742,13 +768,99 @@ CodeGenerator::visitDoubleToString(LDoubleToString *lir)
if (!ool)
return false;
// Try double to integer conversion and run integer to string code.
masm.convertDoubleToInt32(input, temp, ool->entry(), true);
masm.branch32(Assembler::AboveOrEqual, temp, Imm32(StaticStrings::INT_STATIC_LIMIT),
ool->entry());
emitIntToString(temp, output, ool->entry());
masm.movePtr(ImmPtr(&GetIonContext()->runtime->staticStrings().intStaticTable), output);
masm.loadPtr(BaseIndex(output, temp, ScalePointer), output);
masm.bind(ool->rejoin());
return true;
}
typedef JSString *(*PrimitiveToStringFn)(JSContext *, HandleValue);
typedef JSString *(*PrimitiveToStringParFn)(ForkJoinSlice *, HandleValue);
static const VMFunctionsModal PrimitiveToStringInfo = VMFunctionsModal(
FunctionInfo<PrimitiveToStringFn>(ToStringSlow),
FunctionInfo<PrimitiveToStringParFn>(PrimitiveToStringPar));
bool
CodeGenerator::visitPrimitiveToString(LPrimitiveToString *lir)
{
ValueOperand input = ToValue(lir, LPrimitiveToString::Input);
Register output = ToRegister(lir->output());
OutOfLineCode *ool = oolCallVM(PrimitiveToStringInfo, lir, (ArgList(), input),
StoreRegisterTo(output));
if (!ool)
return false;
Label done;
Register tag = masm.splitTagForTest(input);
const JSAtomState &names = GetIonContext()->runtime->names();
// String
if (lir->mir()->input()->mightBeType(MIRType_String)) {
Label notString;
masm.branchTestString(Assembler::NotEqual, tag, &notString);
masm.unboxString(input, output);
masm.jump(&done);
masm.bind(&notString);
}
// Integer
if (lir->mir()->input()->mightBeType(MIRType_Int32)) {
Label notInteger;
masm.branchTestInt32(Assembler::NotEqual, tag, &notInteger);
Register unboxed = ToTempUnboxRegister(lir->tempToUnbox());
unboxed = masm.extractInt32(input, unboxed);
emitIntToString(unboxed, output, ool->entry());
masm.jump(&done);
masm.bind(&notInteger);
}
// Double
if (lir->mir()->input()->mightBeType(MIRType_Double)) {
// Note: no fastpath. Need two extra registers and can only convert doubles
// that fit integers and are smaller than StaticStrings::INT_STATIC_LIMIT.
masm.branchTestDouble(Assembler::Equal, tag, ool->entry());
}
// Undefined
if (lir->mir()->input()->mightBeType(MIRType_Undefined)) {
Label notUndefined;
masm.branchTestUndefined(Assembler::NotEqual, tag, &notUndefined);
masm.movePtr(ImmGCPtr(names.undefined), output);
masm.jump(&done);
masm.bind(&notUndefined);
}
// Null
if (lir->mir()->input()->mightBeType(MIRType_Null)) {
Label notNull;
masm.branchTestNull(Assembler::NotEqual, tag, &notNull);
masm.movePtr(ImmGCPtr(names.null), output);
masm.jump(&done);
masm.bind(&notNull);
}
// Boolean
if (lir->mir()->input()->mightBeType(MIRType_Boolean)) {
Label notBoolean, true_;
masm.branchTestBoolean(Assembler::NotEqual, tag, &notBoolean);
masm.branchTestBooleanTruthy(true, input, &true_);
masm.movePtr(ImmGCPtr(names.false_), output);
masm.jump(&done);
masm.bind(&true_);
masm.movePtr(ImmGCPtr(names.true_), output);
masm.jump(&done);
masm.bind(&notBoolean);
}
#ifdef DEBUG
// Objects are not supported or we see a type that wasn't accounted for.
masm.assumeUnreachable("Unexpected type for MPrimitiveToString.");
#endif
masm.bind(&done);
masm.bind(ool->rejoin());
return true;
}

View File

@ -87,8 +87,11 @@ class CodeGenerator : public CodeGeneratorSpecific
bool visitTestVAndBranch(LTestVAndBranch *lir);
bool visitFunctionDispatch(LFunctionDispatch *lir);
bool visitTypeObjectDispatch(LTypeObjectDispatch *lir);
bool visitBooleanToString(LBooleanToString *lir);
void emitIntToString(Register input, Register output, Label *ool);
bool visitIntToString(LIntToString *lir);
bool visitDoubleToString(LDoubleToString *lir);
bool visitPrimitiveToString(LPrimitiveToString *lir);
bool visitInteger(LInteger *lir);
bool visitRegExp(LRegExp *lir);
bool visitRegExpExec(LRegExpExec *lir);

View File

@ -3097,6 +3097,21 @@ class LTruncateFToInt32 : public LInstructionHelper<1, 1, 1>
}
};
// Convert a boolean value to a string.
class LBooleanToString : public LInstructionHelper<1, 1, 0>
{
public:
LIR_HEADER(BooleanToString)
LBooleanToString(const LAllocation &input) {
setOperand(0, input);
}
const MToString *mir() {
return mir_->toToString();
}
};
// Convert an integer hosted on one definition to a string with a function call.
class LIntToString : public LInstructionHelper<1, 1, 0>
{
@ -3131,6 +3146,28 @@ class LDoubleToString : public LInstructionHelper<1, 1, 1>
}
};
// Convert a primitive to a string with a function call.
class LPrimitiveToString : public LInstructionHelper<1, BOX_PIECES, 1>
{
public:
LIR_HEADER(PrimitiveToString)
LPrimitiveToString(const LDefinition &tempToUnbox)
{
setTemp(0, tempToUnbox);
}
static const size_t Input = 0;
const MToString *mir() {
return mir_->toToString();
}
const LDefinition *tempToUnbox() {
return getTemp(0);
}
};
// No-op instruction that is used to hold the entry snapshot. This simplifies
// register allocation as it doesn't need to sniff the snapshot out of the
// LIRGraph.

View File

@ -36,7 +36,7 @@
_(AbortPar) \
_(InitElem) \
_(InitElemGetterSetter) \
_(MutateProto) \
_(MutateProto) \
_(InitProp) \
_(InitPropGetterSetter) \
_(CheckOverRecursed) \
@ -142,8 +142,10 @@
_(Float32ToInt32) \
_(TruncateDToInt32) \
_(TruncateFToInt32) \
_(BooleanToString) \
_(IntToString) \
_(DoubleToString) \
_(PrimitiveToString) \
_(Start) \
_(OsrEntry) \
_(OsrValue) \

View File

@ -1837,10 +1837,22 @@ LIRGenerator::visitToString(MToString *ins)
MDefinition *opd = ins->input();
switch (opd->type()) {
case MIRType_Null:
case MIRType_Undefined:
case MIRType_Boolean:
MOZ_ASSUME_UNREACHABLE("NYI: Lower MToString");
case MIRType_Null: {
const JSAtomState &names = GetIonContext()->runtime->names();
LPointer *lir = new(alloc()) LPointer(names.null);
return define(lir, ins);
}
case MIRType_Undefined: {
const JSAtomState &names = GetIonContext()->runtime->names();
LPointer *lir = new(alloc()) LPointer(names.undefined);
return define(lir, ins);
}
case MIRType_Boolean: {
LBooleanToString *lir = new(alloc()) LBooleanToString(useRegister(opd));
return define(lir, ins);
}
case MIRType_Double: {
LDoubleToString *lir = new(alloc()) LDoubleToString(useRegister(opd), temp());
@ -1858,6 +1870,16 @@ LIRGenerator::visitToString(MToString *ins)
return assignSafepoint(lir, ins);
}
case MIRType_Value: {
JS_ASSERT(!opd->mightBeType(MIRType_Object));
LPrimitiveToString *lir = new(alloc()) LPrimitiveToString(tempToUnbox());
if (!useBox(lir, LPrimitiveToString::Input, opd))
return false;
if (!define(lir, ins))
return false;
return assignSafepoint(lir, ins);
}
default:
// Objects might be effectful. (see ToPrimitive)
MOZ_ASSUME_UNREACHABLE("unexpected type");

View File

@ -973,9 +973,8 @@ IonBuilder::inlineStringObject(CallInfo &callInfo)
if (callInfo.argc() != 1 || !callInfo.constructing())
return InliningStatus_NotInlined;
// MToString only supports int32 or string values.
MIRType type = callInfo.getArg(0)->type();
if (type != MIRType_Int32 && type != MIRType_String)
// ConvertToString doesn't support objects.
if (callInfo.getArg(0)->mightBeType(MIRType_Object))
return InliningStatus_NotInlined;
JSObject *templateObj = inspector->getTemplateObjectForNative(pc, js_String);
@ -1133,7 +1132,7 @@ IonBuilder::inlineRegExpExec(CallInfo &callInfo)
if (clasp != &RegExpObject::class_)
return InliningStatus_NotInlined;
if (callInfo.getArg(0)->type() != MIRType_String)
if (callInfo.getArg(0)->mightBeType(MIRType_Object))
return InliningStatus_NotInlined;
callInfo.setImplicitlyUsedUnchecked();
@ -1141,9 +1140,13 @@ IonBuilder::inlineRegExpExec(CallInfo &callInfo)
MInstruction *exec = MRegExpExec::New(alloc(), callInfo.thisArg(), callInfo.getArg(0));
current->add(exec);
current->push(exec);
if (!resumeAfter(exec))
return InliningStatus_Error;
if (!pushTypeBarrier(exec, getInlineReturnTypeSet(), true))
return InliningStatus_Error;
return InliningStatus_Inlined;
}
@ -1163,7 +1166,7 @@ IonBuilder::inlineRegExpTest(CallInfo &callInfo)
const Class *clasp = thisTypes ? thisTypes->getKnownClass() : nullptr;
if (clasp != &RegExpObject::class_)
return InliningStatus_NotInlined;
if (callInfo.getArg(0)->type() != MIRType_String)
if (callInfo.getArg(0)->mightBeType(MIRType_Object))
return InliningStatus_NotInlined;
callInfo.setImplicitlyUsedUnchecked();

View File

@ -2060,7 +2060,7 @@ class MAssertFloat32 : public MUnaryInstruction
class MGetDynamicName
: public MAryInstruction<2>,
public MixPolicy<ObjectPolicy<0>, StringPolicy<1> >
public MixPolicy<ObjectPolicy<0>, ConvertToStringPolicy<1> >
{
protected:
MGetDynamicName(MDefinition *scopeChain, MDefinition *name)
@ -3112,6 +3112,12 @@ class MToString : public MUnaryInstruction
MToString(MDefinition *def)
: MUnaryInstruction(def)
{
// Converting an object to a string might be effectful.
JS_ASSERT(!def->mightBeType(MIRType_Object));
// NOP
JS_ASSERT(def->type() != MIRType_String);
setResultType(MIRType_String);
setMovable();
}
@ -3129,7 +3135,7 @@ class MToString : public MUnaryInstruction
return congruentIfOperandsEqual(ins);
}
AliasSet getAliasSet() const {
JS_ASSERT(input()->type() < MIRType_Object);
JS_ASSERT(!input()->mightBeType(MIRType_Object));
return AliasSet::None();
}
};
@ -4223,11 +4229,14 @@ class MMod : public MBinaryArithInstruction
class MConcat
: public MBinaryInstruction,
public BinaryStringPolicy
public MixPolicy<ConvertToStringPolicy<0>, ConvertToStringPolicy<1>>
{
MConcat(MDefinition *left, MDefinition *right)
: MBinaryInstruction(left, right)
{
// At least one input should be definitely string
JS_ASSERT(left->type() == MIRType_String || right->type() == MIRType_String);
setMovable();
setResultType(MIRType_String);
}
@ -4250,12 +4259,15 @@ class MConcat
};
class MConcatPar
: public MTernaryInstruction,
public MixPolicy<StringPolicy<1>, StringPolicy<2> >
: public MTernaryInstruction
{
MConcatPar(MDefinition *slice, MDefinition *left, MDefinition *right)
: MTernaryInstruction(slice, left, right)
{
// Type analysis has already run, before replacing with the parallel
// variant.
JS_ASSERT(left->type() == MIRType_String && right->type() == MIRType_String);
setMovable();
setResultType(MIRType_String);
}
@ -4277,9 +4289,6 @@ class MConcatPar
return getOperand(2);
}
TypePolicy *typePolicy() {
return this;
}
bool congruentTo(MDefinition *ins) const {
return congruentIfOperandsEqual(ins);
}
@ -4872,7 +4881,7 @@ class MRegExp : public MNullaryInstruction
class MRegExpExec
: public MBinaryInstruction,
public MixPolicy<ObjectPolicy<1>, StringPolicy<0> >
public MixPolicy<ConvertToStringPolicy<0>, ObjectPolicy<1>>
{
private:
@ -4909,7 +4918,7 @@ class MRegExpExec
class MRegExpTest
: public MBinaryInstruction,
public MixPolicy<ObjectPolicy<1>, StringPolicy<0> >
public MixPolicy<ObjectPolicy<1>, ConvertToStringPolicy<0> >
{
private:
@ -8967,7 +8976,7 @@ class MNewCallObjectPar : public MBinaryInstruction
class MNewStringObject :
public MUnaryInstruction,
public StringPolicy<0>
public ConvertToStringPolicy<0>
{
CompilerRootObject templateObj_;

View File

@ -295,6 +295,18 @@ jit::DoubleToStringPar(ForkJoinSlice *slice, double d)
return NumberToString<NoGC>(slice, d);
}
JSString *
jit::PrimitiveToStringPar(ForkJoinSlice *slice, HandleValue input)
{
// All other cases are handled in assembly.
JS_ASSERT(input.isDouble() || input.isInt32());
if (input.isInt32())
return Int32ToString<NoGC>(slice, input.toInt32());
return NumberToString<NoGC>(slice, input.toDouble());
}
bool
jit::StringToNumberPar(ForkJoinSlice *slice, JSString *str, double *out)
{

View File

@ -39,6 +39,7 @@ bool SetElementPar(ForkJoinSlice *slice, HandleObject obj, HandleValue index,
JSString *ConcatStringsPar(ForkJoinSlice *slice, HandleString left, HandleString right);
JSFlatString *IntToStringPar(ForkJoinSlice *slice, int i);
JSString *DoubleToStringPar(ForkJoinSlice *slice, double d);
JSString *PrimitiveToStringPar(ForkJoinSlice *slice, HandleValue input);
bool StringToNumberPar(ForkJoinSlice *slice, JSString *str, double *out);
// Binary and unary operator functions on values. These tend to return

View File

@ -87,30 +87,6 @@ ArithPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
return true;
}
bool
BinaryStringPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
{
for (size_t i = 0; i < 2; i++) {
MDefinition *in = ins->getOperand(i);
if (in->type() == MIRType_String)
continue;
MInstruction *replace = nullptr;
if (in->type() == MIRType_Int32 || in->type() == MIRType_Double) {
replace = MToString::New(alloc, in);
} else {
if (in->type() != MIRType_Value)
in = boxAt(alloc, ins, in);
replace = MUnbox::New(alloc, in, MIRType_String, MUnbox::Fallible);
}
ins->block()->insertBefore(ins, replace);
ins->replaceOperand(i, replace);
}
return true;
}
bool
ComparePolicy::adjustInputs(TempAllocator &alloc, MInstruction *def)
{
@ -399,23 +375,18 @@ PowPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
template <unsigned Op>
bool
StringPolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def)
StringPolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins)
{
MDefinition *in = def->getOperand(Op);
MDefinition *in = ins->getOperand(Op);
if (in->type() == MIRType_String)
return true;
MInstruction *replace;
if (in->type() == MIRType_Int32 || in->type() == MIRType_Double) {
replace = MToString::New(alloc, in);
} else {
if (in->type() != MIRType_Value)
in = boxAt(alloc, def, in);
replace = MUnbox::New(alloc, in, MIRType_String, MUnbox::Fallible);
}
if (in->type() != MIRType_Value)
in = boxAt(alloc, ins, in);
def->block()->insertBefore(def, replace);
def->replaceOperand(Op, replace);
MUnbox *replace = MUnbox::New(alloc, in, MIRType_String, MUnbox::Fallible);
ins->block()->insertBefore(ins, replace);
ins->replaceOperand(Op, replace);
return true;
}
@ -423,6 +394,32 @@ template bool StringPolicy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruc
template bool StringPolicy<1>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
template bool StringPolicy<2>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
template <unsigned Op>
bool
ConvertToStringPolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins)
{
MDefinition *in = ins->getOperand(Op);
if (in->type() == MIRType_String)
return true;
MInstruction *replace;
if (in->mightBeType(MIRType_Object)) {
if (in->type() != MIRType_Value)
in = boxAt(alloc, ins, in);
replace = MUnbox::New(alloc, in, MIRType_String, MUnbox::Fallible);
} else {
replace = MToString::New(alloc, in);
}
ins->block()->insertBefore(ins, replace);
ins->replaceOperand(Op, replace);
return true;
}
template bool ConvertToStringPolicy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
template bool ConvertToStringPolicy<1>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
template <unsigned Op>
bool
IntPolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def)

View File

@ -53,12 +53,6 @@ class ArithPolicy : public BoxInputsPolicy
bool adjustInputs(TempAllocator &alloc, MInstruction *def);
};
class BinaryStringPolicy : public BoxInputsPolicy
{
public:
bool adjustInputs(TempAllocator &alloc, MInstruction *def);
};
class BitwisePolicy : public BoxInputsPolicy
{
protected:
@ -124,6 +118,17 @@ class StringPolicy : public BoxInputsPolicy
}
};
// Expect a string for operand Op. Else a ToString instruction is inserted.
template <unsigned Op>
class ConvertToStringPolicy : public BoxInputsPolicy
{
public:
static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
bool adjustInputs(TempAllocator &alloc, MInstruction *def) {
return staticAdjustInputs(alloc, def);
}
};
// Expect an Int for operand Op. If the input is a Value, it is unboxed.
template <unsigned Op>
class IntPolicy : public BoxInputsPolicy

View File

@ -986,7 +986,7 @@ class AutoNameVector : public AutoVectorRooter<PropertyName *>
}
HandlePropertyName operator[](size_t i) const {
return HandlePropertyName::fromMarkedLocation(&BaseType::operator[](i));
return HandlePropertyName::fromMarkedLocation(&begin()[i]);
}
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER

View File

@ -2155,9 +2155,13 @@ nsXPCConstructor::CallOrConstruct(nsIXPConnectWrappedNative *wrapper,JSContext *
return ThrowAndFail(NS_ERROR_XPC_CANT_CREATE_WN, cx, _retval);
}
Value argv[1] = {ObjectValue(*iidObj)};
JS::AutoValueVector argv(cx);
MOZ_ALWAYS_TRUE(argv.resize(1));
argv[0].setObject(*iidObj);
RootedValue rval(cx);
if (!JS_CallFunctionName(cx, cidObj, "createInstance", 1, argv, rval.address()) ||
if (!JS_CallFunctionName(cx, cidObj, "createInstance", 1, argv.begin(),
rval.address()) ||
rval.isPrimitive()) {
// createInstance will have thrown an exception
*_retval = false;

View File

@ -238,8 +238,11 @@ nsXPCWrappedJSClass::CallQueryInterfaceOnJSObject(JSContext* cx,
{
AutoSaveContextOptions asco(cx);
ContextOptionsRef(cx).setDontReportUncaught(true);
jsval args[1] = {OBJECT_TO_JSVAL(id)};
success = JS_CallFunctionValue(cx, jsobj, fun, 1, args, retval.address());
JS::AutoValueVector argv(cx);
MOZ_ALWAYS_TRUE(argv.resize(1));
argv[0].setObject(*id);
success = JS_CallFunctionValue(cx, jsobj, fun, 1, argv.begin(),
retval.address());
}
if (!success && JS_IsExceptionPending(cx)) {

View File

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html class="reftest-print">
<head><meta charset="utf-8"></head>
<body>
<div style="height:3in">Tall div. (Scroll to end.)</div>
<div>IS THIS TEXT VISIBLE IN PRINT PREVIEW?</div>
<div>[clear:left]</div>
</body>
</html>

View File

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html class="reftest-print">
<head><meta charset="utf-8"></head>
<body>
<div style="float: left">
<table cellpadding=0 cellspacing=0>
<tr>
<td>
<div style="height:3in">Tall div. (Scroll to end.)</div>
<div>IS THIS TEXT VISIBLE IN PRINT PREVIEW?</div>
</td>
</tr>
</table>
</div>
<div style="clear: left">[clear:left]</div>
</body>
</html>

View File

@ -1,3 +1,4 @@
== bug785684-x.html bug785684-ref.html
== bug785684-y.html bug785684-ref.html
== table-row-pagination.html table-row-pagination-ref.html
== 963441.html 963441-ref.html

View File

@ -2956,7 +2956,14 @@ nsTableFrame::ReflowChildren(nsTableReflowState& aReflowState,
mFrames.InsertFrame(nullptr, kidFrame, kidNextInFlow);
// and in rowGroups after childX so that it will get pushed below.
rowGroups.InsertElementAt(childX + 1,
static_cast <nsTableRowGroupFrame*>(kidNextInFlow));
static_cast<nsTableRowGroupFrame*>(kidNextInFlow));
} else if (kidNextInFlow == kidFrame->GetNextSibling()) {
// OrderRowGroups excludes NIFs in the child list from 'rowGroups'
// so we deal with that here to make sure they get pushed.
MOZ_ASSERT(!rowGroups.Contains(kidNextInFlow),
"OrderRowGroups must not put our NIF in 'rowGroups'");
rowGroups.InsertElementAt(childX + 1,
static_cast<nsTableRowGroupFrame*>(kidNextInFlow));
}
// We've used up all of our available space so push the remaining

View File

@ -420,6 +420,9 @@ audiounit_stream_init(cubeb * context, cubeb_stream ** stream, char const * stre
return CUBEB_ERROR;
}
// Setting the latency doesn't work well for USB headsets (eg. plantronics).
// Keep the default latency for now.
#if 0
if (buffer_size < default_buffer_size) {
/* Set the maximum number of frame that the render callback will ask for,
* effectively setting the latency of the stream. This is process-wide. */
@ -430,6 +433,7 @@ audiounit_stream_init(cubeb * context, cubeb_stream ** stream, char const * stre
return CUBEB_ERROR;
}
}
#endif
r = AudioUnitSetProperty(stm->unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
0, &ss, sizeof(ss));

View File

@ -4125,8 +4125,6 @@ pref("layers.offmainthreadcomposition.force-basic", false);
// Whether to animate simple opacity and transforms on the compositor
pref("layers.offmainthreadcomposition.async-animations", false);
// Whether to prefer normal memory over shared memory. Ignored with cross-process compositing
pref("layers.prefer-memory-over-shmem", true);
pref("layers.bufferrotation.enabled", true);

View File

@ -681,13 +681,14 @@ ProxyAutoConfig::GetProxyForURI(const nsCString &aTestURI,
JS::RootedString hostString(cx, JS_NewStringCopyZ(cx, aTestHost.get()));
if (uriString && hostString) {
JS::RootedValue uriValue(cx, STRING_TO_JSVAL(uriString));
JS::RootedValue hostValue(cx, STRING_TO_JSVAL(hostString));
JS::AutoValueVector argv(cx);
MOZ_ALWAYS_TRUE(argv.resize(2));
argv[0].setString(uriString);
argv[1].setString(hostString);
JS::Value argv[2] = { uriValue, hostValue };
JS::Rooted<JS::Value> rval(cx);
bool ok = JS_CallFunctionName(cx, mJSRuntime->Global(),
"FindProxyForURL", 2, argv, rval.address());
"FindProxyForURL", 2, argv.begin(), rval.address());
if (ok && rval.isString()) {
nsDependentJSString pacString;

View File

@ -25,7 +25,7 @@
"tests": ["a11yr", "ts_paint", "tpaint"]
},
"svgr": {
"tests": ["tsvgx", "tsvgr_opacity", "tart", "tscrollx"]
"tests": ["tsvgx", "tsvgr_opacity", "tart", "tscrollx", "cart"]
},
"tp5o": {
"tests": ["tp5o"],

View File

@ -753,9 +753,7 @@ NativeKey::IsFollowedByCharMessage() const
return false;
}
}
return (nextMsg.message == WM_CHAR ||
nextMsg.message == WM_SYSCHAR ||
nextMsg.message == WM_DEADCHAR);
return IsCharMessage(nextMsg);
}
bool
@ -770,7 +768,7 @@ NativeKey::IsFollowedByDeadCharMessage() const
return false;
}
}
return (nextMsg.message == WM_DEADCHAR);
return IsDeadCharMessage(nextMsg);
}
bool
@ -984,7 +982,7 @@ NativeKey::DispatchKeyEvent(WidgetKeyboardEvent& aKeyEvent,
bool
NativeKey::HandleKeyDownMessage(bool* aEventDispatched) const
{
MOZ_ASSERT(mMsg.message == WM_KEYDOWN || mMsg.message == WM_SYSKEYDOWN);
MOZ_ASSERT(IsKeyDownMessage());
if (aEventDispatched) {
*aEventDispatched = false;
@ -1108,9 +1106,8 @@ bool
NativeKey::HandleCharMessage(const MSG& aCharMsg,
bool* aEventDispatched) const
{
MOZ_ASSERT(mMsg.message == WM_KEYDOWN || mMsg.message == WM_SYSKEYDOWN ||
mMsg.message == WM_CHAR || mMsg.message == WM_SYSCHAR);
MOZ_ASSERT(aCharMsg.message == WM_CHAR || aCharMsg.message == WM_SYSCHAR);
MOZ_ASSERT(IsKeyDownMessage() || IsPrintableCharMessage(mMsg));
MOZ_ASSERT(IsPrintableCharMessage(aCharMsg.message));
if (aEventDispatched) {
*aEventDispatched = false;
@ -1220,7 +1217,7 @@ NativeKey::HandleCharMessage(const MSG& aCharMsg,
bool
NativeKey::HandleKeyUpMessage(bool* aEventDispatched) const
{
MOZ_ASSERT(mMsg.message == WM_KEYUP || mMsg.message == WM_SYSKEYUP);
MOZ_ASSERT(IsKeyUpMessage());
if (aEventDispatched) {
*aEventDispatched = false;
@ -1243,7 +1240,7 @@ NativeKey::HandleKeyUpMessage(bool* aEventDispatched) const
bool
NativeKey::NeedsToHandleWithoutFollowingCharMessages() const
{
MOZ_ASSERT(mMsg.message == WM_KEYDOWN || mMsg.message == WM_SYSKEYDOWN);
MOZ_ASSERT(IsKeyDownMessage());
// Enter and backspace are always handled here to avoid for example the
// confusion between ctrl-enter and ctrl-J.
@ -1282,9 +1279,9 @@ NativeKey::RemoveFollowingCharMessage() const
}
MSG msg;
if (!WinUtils::GetMessage(&msg, mMsg.hwnd, WM_KEYFIRST, WM_KEYLAST) ||
!(msg.message == WM_CHAR || msg.message == WM_SYSCHAR ||
msg.message == WM_DEADCHAR)) {
if (!WinUtils::PeekMessage(&msg, mMsg.hwnd, WM_KEYFIRST, WM_KEYLAST,
PM_REMOVE | PM_NOYIELD) ||
!IsCharMessage(msg)) {
MOZ_CRASH("We lost the following char message");
}
@ -1314,7 +1311,8 @@ NativeKey::RemoveMessageAndDispatchPluginEvent(UINT aFirstMsg,
}
MOZ_ASSERT(found, "Fake char message must be found");
} else {
WinUtils::GetMessage(&msg, mMsg.hwnd, aFirstMsg, aLastMsg);
WinUtils::PeekMessage(&msg, mMsg.hwnd, aFirstMsg, aLastMsg,
PM_REMOVE | PM_NOYIELD);
}
if (mWidget->Destroyed()) {
MOZ_CRASH("NativeKey tries to dispatch a plugin event on destroyed widget");
@ -1326,7 +1324,7 @@ NativeKey::RemoveMessageAndDispatchPluginEvent(UINT aFirstMsg,
bool
NativeKey::DispatchPluginEventsAndDiscardsCharMessages() const
{
MOZ_ASSERT(mMsg.message == WM_KEYDOWN || mMsg.message == WM_SYSKEYDOWN);
MOZ_ASSERT(IsKeyDownMessage());
if (mFakeCharMsgs) {
for (uint32_t i = 0; i < mFakeCharMsgs->Length(); i++) {
@ -1346,9 +1344,7 @@ NativeKey::DispatchPluginEventsAndDiscardsCharMessages() const
bool gotMsg =
WinUtils::PeekMessage(&msg, mMsg.hwnd, WM_KEYFIRST, WM_KEYLAST,
PM_NOREMOVE | PM_NOYIELD);
while (gotMsg &&
(msg.message == WM_CHAR || msg.message == WM_SYSCHAR ||
msg.message == WM_DEADCHAR)) {
while (gotMsg && IsCharMessage(msg)) {
if (RemoveMessageAndDispatchPluginEvent(WM_KEYFIRST, WM_KEYLAST)) {
return true;
}
@ -1369,7 +1365,7 @@ NativeKey::DispatchPluginEventsAndDiscardsCharMessages() const
bool
NativeKey::DispatchKeyPressEventsWithKeyboardLayout() const
{
MOZ_ASSERT(mMsg.message == WM_KEYDOWN || mMsg.message == WM_SYSKEYDOWN);
MOZ_ASSERT(IsKeyDownMessage());
MOZ_ASSERT(!mIsDeadKey);
KeyboardLayout* keyboardLayout = KeyboardLayout::GetInstance();
@ -1533,11 +1529,11 @@ NativeKey::DispatchKeyPressEventsWithKeyboardLayout() const
bool
NativeKey::DispatchKeyPressEventForFollowingCharMessage() const
{
MOZ_ASSERT(mMsg.message == WM_KEYDOWN || mMsg.message == WM_SYSKEYDOWN);
MOZ_ASSERT(IsKeyDownMessage());
MSG msg = RemoveFollowingCharMessage();
if (mFakeCharMsgs) {
if (msg.message == WM_DEADCHAR) {
if (IsDeadCharMessage(msg)) {
return false;
}
#ifdef DEBUG
@ -1566,7 +1562,7 @@ NativeKey::DispatchKeyPressEventForFollowingCharMessage() const
return HandleCharMessage(msg);
}
if (msg.message == WM_DEADCHAR) {
if (IsDeadCharMessage(msg)) {
if (!mWidget->PluginHasFocus()) {
return false;
}
@ -1576,7 +1572,7 @@ NativeKey::DispatchKeyPressEventForFollowingCharMessage() const
bool defaultPrevented = HandleCharMessage(msg);
// If a syschar keypress wasn't processed, Windows may want to
// handle it to activate a native menu.
if (!defaultPrevented && msg.message == WM_SYSCHAR) {
if (!defaultPrevented && IsSysCharMessage(msg)) {
::DefWindowProcW(msg.hwnd, msg.message, msg.wParam, msg.lParam);
}
return defaultPrevented;
@ -2651,7 +2647,8 @@ RedirectedKeyDownMessageManager::RemoveNextCharMessage(HWND aWnd)
if (WinUtils::PeekMessage(&msg, aWnd, WM_KEYFIRST, WM_KEYLAST,
PM_NOREMOVE | PM_NOYIELD) &&
(msg.message == WM_CHAR || msg.message == WM_SYSCHAR)) {
WinUtils::GetMessage(&msg, aWnd, msg.message, msg.message);
WinUtils::PeekMessage(&msg, aWnd, msg.message, msg.message,
PM_REMOVE | PM_NOYIELD);
}
}

View File

@ -338,6 +338,42 @@ private:
{
return (mMsg.message == WM_KEYDOWN || mMsg.message == WM_SYSKEYDOWN);
}
bool IsKeyUpMessage() const
{
return (mMsg.message == WM_KEYUP || mMsg.message == WM_SYSKEYUP);
}
bool IsPrintableCharMessage(const MSG& aMSG) const
{
return IsPrintableCharMessage(aMSG.message);
}
bool IsPrintableCharMessage(UINT aMessage) const
{
return (aMessage == WM_CHAR || aMessage == WM_SYSCHAR);
}
bool IsCharMessage(const MSG& aMSG) const
{
return IsCharMessage(aMSG.message);
}
bool IsCharMessage(UINT aMessage) const
{
return (IsPrintableCharMessage(aMessage) || IsDeadCharMessage(aMessage));
}
bool IsDeadCharMessage(const MSG& aMSG) const
{
return IsDeadCharMessage(aMSG.message);
}
bool IsDeadCharMessage(UINT aMessage) const
{
return (aMessage == WM_DEADCHAR || aMessage == WM_SYSDEADCHAR);
}
bool IsSysCharMessage(const MSG& aMSG) const
{
return IsSysCharMessage(aMSG.message);
}
bool IsSysCharMessage(UINT aMessage) const
{
return (aMessage == WM_SYSCHAR || aMessage == WM_SYSDEADCHAR);
}
bool IsFollowedByCharMessage() const;
bool IsFollowedByDeadCharMessage() const;
MSG RemoveFollowingCharMessage() const;

View File

@ -890,15 +890,13 @@ nsTextStore::RequestLock(DWORD dwLockFlags,
if (!mLock) {
// put on lock
mLock = dwLockFlags & (~TS_LF_SYNC);
PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
("TSF: 0x%p Locking (%s) >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"
">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"
">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>",
this, GetLockFlagNameStr(mLock).get()));
*phrSession = mSink->OnLockGranted(mLock);
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
("TSF: 0x%p Unlocked (%s) <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
"<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
"<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<",
this, GetLockFlagNameStr(mLock).get()));
DidLockGranted();
@ -907,19 +905,17 @@ nsTextStore::RequestLock(DWORD dwLockFlags,
mLockQueued = 0;
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
("TSF: 0x%p Locking for the request in the queue (%s) >>>>>>>>>>>>>>"
">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"
">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>",
this, GetLockFlagNameStr(mLock).get()));
mSink->OnLockGranted(mLock);
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
("TSF: 0x%p Unlocked (%s) <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
"<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
"<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<",
this, GetLockFlagNameStr(mLock).get()));
DidLockGranted();
}
mLock = 0;
PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
("TSF: 0x%p nsTextStore::RequestLock() succeeded: *phrSession=%s",
this, GetTextStoreReturnValueName(*phrSession)));
return S_OK;
@ -1178,7 +1174,7 @@ nsTextStore::FlushPendingActions()
if (notifyTSFOfLayoutChange && mWidget && !mWidget->Destroyed()) {
if (mSink) {
PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
("TSF: 0x%p nsTextStore::FlushPendingActions(), "
"calling ITextStoreACPSink::OnLayoutChange()...", this));
mSink->OnLayoutChange(TS_LC_CHANGE, TEXTSTORE_DEFAULT_VIEW);
@ -1191,7 +1187,7 @@ nsTextStore::FlushPendingActions()
mContext->QueryInterface(IID_ITfContextOwnerServices,
getter_AddRefs(service));
if (service) {
PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
("TSF: 0x%p nsTextStore::FlushPendingActions(), "
"calling ITfContextOwnerServices::OnLayoutChange()...", this));
service->OnLayoutChange();
@ -1200,6 +1196,9 @@ nsTextStore::FlushPendingActions()
}
if (mNotifySelectionChange && mSink && mWidget && !mWidget->Destroyed()) {
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
("TSF: 0x%p nsTextStore::FlushPendingActions(), "
"calling ITextStoreACPSink::OnSelectionChange()...", this));
mSink->OnSelectionChange();
}
mNotifySelectionChange = false;
@ -1749,9 +1748,12 @@ nsTextStore::SetSelectionInternal(const TS_SELECTION_ACP* pSelection,
bool aDispatchTextEvent)
{
PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
("TSF: 0x%p nsTextStore::SetSelectionInternal(pSelection=%ld-%ld, "
"aDispatchTextEvent=%s), IsComposing()=%s",
("TSF: 0x%p nsTextStore::SetSelectionInternal(pSelection={ "
"acpStart=%ld, acpEnd=%ld, style={ ase=%s, fInterimChar=%s} }, "
"aDispatchTextEvent=%s), mComposition.IsComposing()=%s",
this, pSelection->acpStart, pSelection->acpEnd,
GetActiveSelEndName(pSelection->style.ase),
GetBoolName(pSelection->style.fInterimChar),
GetBoolName(aDispatchTextEvent),
GetBoolName(mComposition.IsComposing())));
@ -1812,8 +1814,15 @@ nsTextStore::SetSelection(ULONG ulCount,
const TS_SELECTION_ACP *pSelection)
{
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
("TSF: 0x%p nsTextStore::SetSelection(ulCount=%lu)",
this, ulCount));
("TSF: 0x%p nsTextStore::SetSelection(ulCount=%lu, pSelection=%p { "
"acpStart=%ld, acpEnd=%ld, style={ ase=%s, fInterimChar=%s } }), "
"mComposition.IsComposing()=%s",
this, ulCount, pSelection,
pSelection ? pSelection->acpStart : 0,
pSelection ? pSelection->acpEnd : 0,
pSelection ? GetActiveSelEndName(pSelection->style.ase) : "",
pSelection ? GetBoolName(pSelection->style.fInterimChar) : "",
GetBoolName(mComposition.IsComposing())));
if (!IsReadWriteLocked()) {
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
@ -1861,7 +1870,7 @@ nsTextStore::GetText(LONG acpStart,
("TSF: 0x%p nsTextStore::GetText(acpStart=%ld, acpEnd=%ld, pchPlain=0x%p, "
"cchPlainReq=%lu, pcchPlainOut=0x%p, prgRunInfo=0x%p, ulRunInfoReq=%lu, "
"pulRunInfoOut=0x%p, pacpNext=0x%p), mComposition={ mStart=%ld, "
"mString.Length()=%lu IsComposing()=%s }",
"mString.Length()=%lu, IsComposing()=%s }",
this, acpStart, acpEnd, pchPlain, cchPlainReq, pcchPlainOut,
prgRunInfo, ulRunInfoReq, pulRunInfoOut, pacpNext,
mComposition.mStart, mComposition.mString.Length(),
@ -1960,8 +1969,9 @@ nsTextStore::SetText(DWORD dwFlags,
TS_TEXTCHANGE *pChange)
{
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
("TSF: 0x%p nsTextStore::SetText(dwFlags=%s, acpStart=%ld, acpEnd=%ld, "
"pchText=0x%p \"%s\", cch=%lu, pChange=0x%p), IsComposing()=%s",
("TSF: 0x%p nsTextStore::SetText(dwFlags=%s, acpStart=%ld, "
"acpEnd=%ld, pchText=0x%p \"%s\", cch=%lu, pChange=0x%p), "
"mComposition.IsComposing()=%s",
this, dwFlags == TS_ST_CORRECTION ? "TS_ST_CORRECTION" :
"not-specified",
acpStart, acpEnd, pchText,
@ -2106,9 +2116,9 @@ nsTextStore::ProcessScopeRequest(DWORD dwFlags,
const TS_ATTRID *paFilterAttrs)
{
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
("TSF: 0x%p nsTextStore::ProcessScopeRequest() called "
"cFilterAttrs=%d dwFlags=%s", this, cFilterAttrs,
GetFindFlagName(dwFlags).get()));
("TSF: 0x%p nsTextStore::ProcessScopeRequest(dwFlags=%s, "
"cFilterAttrs=%ld",
this, GetFindFlagName(dwFlags).get(), cFilterAttrs));
// This is a little weird! RequestSupportedAttrs gives us advanced notice
// of a support query via RetrieveRequestedAttrs for a specific attribute.
@ -2122,7 +2132,8 @@ nsTextStore::ProcessScopeRequest(DWORD dwFlags,
for (uint32_t idx = 0; idx < cFilterAttrs; ++idx) {
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
("TSF: 0x%p nsTextStore::ProcessScopeRequest() "
"requested attr=%s", this, GetCLSIDNameStr(paFilterAttrs[idx]).get()));
"requested attr=%s",
this, GetCLSIDNameStr(paFilterAttrs[idx]).get()));
if (IsEqualGUID(paFilterAttrs[idx], GUID_PROP_INPUTSCOPE)) {
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
("TSF: 0x%p nsTextStore::ProcessScopeRequest() "
@ -2146,9 +2157,9 @@ nsTextStore::RequestSupportedAttrs(DWORD dwFlags,
const TS_ATTRID *paFilterAttrs)
{
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
("TSF: 0x%p nsTextStore::RequestSupportedAttrs() called "
"cFilterAttrs=%d dwFlags=%s", this, cFilterAttrs,
GetFindFlagName(dwFlags).get()));
("TSF: 0x%p nsTextStore::RequestSupportedAttrs(dwFlags=%s, "
"cFilterAttrs=%lu)",
this, GetFindFlagName(dwFlags).get(), cFilterAttrs));
return ProcessScopeRequest(dwFlags, cFilterAttrs, paFilterAttrs);
}
@ -2160,9 +2171,9 @@ nsTextStore::RequestAttrsAtPosition(LONG acpPos,
DWORD dwFlags)
{
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
("TSF: 0x%p nsTextStore::RequestAttrsAtPosition() called "
"acpPos=%d cFilterAttrs=%d dwFlags=%s", this, acpPos, cFilterAttrs,
GetFindFlagName(dwFlags).get()));
("TSF: 0x%p nsTextStore::RequestAttrsAtPosition(acpPos=%ld, "
"cFilterAttrs=%lu, dwFlags=%s)",
this, acpPos, cFilterAttrs, GetFindFlagName(dwFlags).get()));
return ProcessScopeRequest(dwFlags | TS_ATTR_FIND_WANT_VALUE,
cFilterAttrs, paFilterAttrs);
@ -2175,8 +2186,10 @@ nsTextStore::RequestAttrsTransitioningAtPosition(LONG acpPos,
DWORD dwFlags)
{
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
("TSF: 0x%p nsTextStore::RequestAttrsTransitioningAtPosition() called "
"but not supported (S_OK)", this));
("TSF: 0x%p nsTextStore::RequestAttrsTransitioningAtPosition("
"acpPos=%ld, cFilterAttrs=%lu, dwFlags=%s) called but not supported "
"(S_OK)",
this, acpPos, cFilterAttrs, GetFindFlagName(dwFlags).get()));
// no per character attributes defined
return S_OK;
@ -2194,7 +2207,7 @@ nsTextStore::FindNextAttrTransition(LONG acpStart,
{
if (!pacpNext || !pfFound || !plFoundOffset) {
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
("TSF: 0x%p nsTextStore::FindNextAttrTransition() FAILED due to "
("TSF: 0x%p nsTextStore::FindNextAttrTransition() FAILED due to "
"null argument", this));
return E_INVALIDARG;
}
@ -2816,7 +2829,7 @@ nsTextStore::RecordCompositionStartAction(ITfCompositionView* pComposition,
currentContent.StartComposition(pComposition, *action, aPreserveSelection);
PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
("TSF: 0x%p nsTextStore::RecordCompositionStartAction() succeeded: "
"mComposition={ mStart=%ld, mString.Length()=%ld, "
"mSelection={ acpStart=%ld, acpEnd=%ld, style.ase=%s, "
@ -3094,7 +3107,7 @@ nsTextStore::OnFocusChange(bool aGotFocus,
IMEState::Enabled aIMEEnabled)
{
PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
("TSF: nsTextStore::OnFocusChange(aGotFocus=%s, "
("TSF: nsTextStore::OnFocusChange(aGotFocus=%s, "
"aFocusedWidget=0x%p, aIMEEnabled=%s), sTsfThreadMgr=0x%p, "
"sTsfTextStore=0x%p",
GetBoolName(aGotFocus), aFocusedWidget,
@ -3165,7 +3178,7 @@ nsTextStore::OnTextChangeInternal(uint32_t aStart,
uint32_t aNewEnd)
{
PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
("TSF: 0x%p nsTextStore::OnTextChangeInternal(aStart=%lu, "
("TSF: 0x%p nsTextStore::OnTextChangeInternal(aStart=%lu, "
"aOldEnd=%lu, aNewEnd=%lu), mSink=0x%p, mSinkMask=%s, "
"mComposition.IsComposing()=%s",
this, aStart, aOldEnd, aNewEnd, mSink.get(),
@ -3221,7 +3234,7 @@ nsresult
nsTextStore::OnSelectionChangeInternal(void)
{
PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
("TSF: 0x%p nsTextStore::OnSelectionChangeInternal(), "
("TSF: 0x%p nsTextStore::OnSelectionChangeInternal(), "
"mSink=0x%p, mSinkMask=%s, mIsRecordingActionsWithoutLock=%s, "
"mComposition.IsComposing()=%s",
this, mSink.get(), GetSinkMaskNameStr(mSinkMask).get(),
@ -3292,7 +3305,7 @@ nsTextStore::CreateNativeCaret()
}
PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
("TSF: 0x%p nsTextStore::CreateNativeCaret(), "
("TSF: 0x%p nsTextStore::CreateNativeCaret(), "
"mComposition.IsComposing()=%s",
this, GetBoolName(mComposition.IsComposing())));
@ -3443,7 +3456,7 @@ void
nsTextStore::CommitCompositionInternal(bool aDiscard)
{
PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
("TSF: 0x%p nsTextStore::CommitCompositionInternal(aDiscard=%s), "
("TSF: 0x%p nsTextStore::CommitCompositionInternal(aDiscard=%s), "
"mSink=0x%p, mContext=0x%p, mComposition.mView=0x%p, "
"mComposition.mString=\"%s\"",
this, GetBoolName(aDiscard), mSink.get(), mContext.get(),
@ -3684,7 +3697,7 @@ nsTextStore::GetTIPDescription(REFCLSID aTextService, LANGID aLangID,
&description);
if (FAILED(hr)) {
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
("TSF: nsTextStore::InitActiveTIPDescription() FAILED due to "
("TSF: nsTextStore::InitActiveTIPDescription() FAILED due to "
"GetLanguageProfileDescription() failure, hr=0x%08X", hr));
return;
}
@ -4122,7 +4135,7 @@ nsTextStore::CurrentKeyboardLayoutHasIME()
// keyboard layout has IME.
if (IsVistaOrLater()) {
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
("TSF: nsTextStore::CurrentKeyboardLayoutHasIME() FAILED to query "
("TSF: nsTextStore::CurrentKeyboardLayoutHasIME() FAILED to query "
"ITfInputProcessorProfileMgr"));
return false;
}
@ -4139,7 +4152,7 @@ nsTextStore::CurrentKeyboardLayoutHasIME()
}
if (FAILED(hr)) {
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
("TSF: nsTextStore::CurrentKeyboardLayoutHasIME() FAILED to retreive "
("TSF: nsTextStore::CurrentKeyboardLayoutHasIME() FAILED to retreive "
"active profile"));
return false;
}

View File

@ -164,22 +164,22 @@ nsHTTPIndex::OnFTPControlLog(bool server, const char *msg)
JS::Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx));
NS_ENSURE_TRUE(global, NS_OK);
JS::Value params[2];
nsString unicodeMsg;
unicodeMsg.AssignWithConversion(msg);
JSString* jsMsgStr = JS_NewUCStringCopyZ(cx, unicodeMsg.get());
NS_ENSURE_TRUE(jsMsgStr, NS_ERROR_OUT_OF_MEMORY);
params[0] = BOOLEAN_TO_JSVAL(server);
params[1] = STRING_TO_JSVAL(jsMsgStr);
JS::AutoValueVector params(cx);
MOZ_ALWAYS_TRUE(params.resize(2));
params[0].setBoolean(server);
params[1].setString(jsMsgStr);
JS::Rooted<JS::Value> val(cx);
JS_CallFunctionName(cx,
global,
"OnFTPControlLog",
2,
params,
params.begin(),
val.address());
return NS_OK;
}