mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 22:01:30 +00:00
Merge m-c to fx-team.
This commit is contained in:
commit
4dd29179e9
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
|
@ -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_
|
||||
|
@ -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;
|
||||
|
@ -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_,
|
@ -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 {
|
@ -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); \
|
@ -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
134
gfx/ots/ots-woff2.patch
Normal 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);
|
||||
}
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
#define OTS_GASP_H_
|
||||
|
||||
#include <new>
|
||||
#include <utility> // std::pair
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "ots.h"
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
#define OTS_GLYF_H_
|
||||
|
||||
#include <new>
|
||||
#include <utility> // std::pair
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "ots.h"
|
||||
|
@ -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;
|
||||
|
@ -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
|
@ -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_
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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(<sh->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
608
gfx/ots/src/math.cc
Normal 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
25
gfx/ots/src/math_.h
Normal 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
|
||||
|
@ -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;
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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':
|
||||
|
@ -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
|
||||
//
|
||||
|
58
js/src/jit-test/tests/ion/bug964229-2.js
Normal file
58
js/src/jit-test/tests/ion/bug964229-2.js
Normal 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/, {}));
|
||||
|
||||
|
26
js/src/jit-test/tests/ion/bug964229.js
Normal file
26
js/src/jit-test/tests/ion/bug964229.js
Normal 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);
|
||||
}
|
||||
}
|
@ -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:
|
||||
//
|
||||
|
@ -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, ¬String);
|
||||
masm.unboxString(input, output);
|
||||
masm.jump(&done);
|
||||
masm.bind(¬String);
|
||||
}
|
||||
|
||||
// Integer
|
||||
if (lir->mir()->input()->mightBeType(MIRType_Int32)) {
|
||||
Label notInteger;
|
||||
masm.branchTestInt32(Assembler::NotEqual, tag, ¬Integer);
|
||||
Register unboxed = ToTempUnboxRegister(lir->tempToUnbox());
|
||||
unboxed = masm.extractInt32(input, unboxed);
|
||||
emitIntToString(unboxed, output, ool->entry());
|
||||
masm.jump(&done);
|
||||
masm.bind(¬Integer);
|
||||
}
|
||||
|
||||
// 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, ¬Undefined);
|
||||
masm.movePtr(ImmGCPtr(names.undefined), output);
|
||||
masm.jump(&done);
|
||||
masm.bind(¬Undefined);
|
||||
}
|
||||
|
||||
// Null
|
||||
if (lir->mir()->input()->mightBeType(MIRType_Null)) {
|
||||
Label notNull;
|
||||
masm.branchTestNull(Assembler::NotEqual, tag, ¬Null);
|
||||
masm.movePtr(ImmGCPtr(names.null), output);
|
||||
masm.jump(&done);
|
||||
masm.bind(¬Null);
|
||||
}
|
||||
|
||||
// Boolean
|
||||
if (lir->mir()->input()->mightBeType(MIRType_Boolean)) {
|
||||
Label notBoolean, true_;
|
||||
masm.branchTestBoolean(Assembler::NotEqual, tag, ¬Boolean);
|
||||
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(¬Boolean);
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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) \
|
||||
|
@ -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");
|
||||
|
@ -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();
|
||||
|
@ -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_;
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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)) {
|
||||
|
9
layout/reftests/table-overflow/963441-ref.html
Normal file
9
layout/reftests/table-overflow/963441-ref.html
Normal 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>
|
17
layout/reftests/table-overflow/963441.html
Normal file
17
layout/reftests/table-overflow/963441.html
Normal 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>
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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"],
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user