Remove woff2 from third_party (#4781)

Bazel's WORKSPACE file is deprecated, and we haven't worked on the woff2
example in ages. Rather than investing time into keeping it around,
remove it and we can revive it when we're ready.
This commit is contained in:
Jon Ross-Perkins
2025-01-10 01:27:40 +00:00
committed by GitHub
parent 82a346730a
commit 43e68751c6
38 changed files with 0 additions and 5235 deletions
-21
View File
@@ -6,27 +6,6 @@ workspace(name = "carbon")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
###############################################################################
# Example conversion repositories
###############################################################################
local_repository(
name = "brotli",
path = "third_party/examples/brotli/original",
)
new_local_repository(
name = "woff2",
build_file = "third_party/examples/woff2/BUILD.original",
path = "third_party/examples/woff2/original",
workspace_file = "third_party/examples/woff2/WORKSPACE.original",
)
local_repository(
name = "woff2_carbon",
path = "third_party/examples/woff2/carbon",
)
###############################################################################
# Treesitter rules
###############################################################################
-106
View File
@@ -1,106 +0,0 @@
# Part of the Carbon Language project, under the Apache License v2.0 with LLVM
# Exceptions. See /LICENSE for license information.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
# Rules are adapted from CMakeLists.txt.
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library")
package(
default_visibility = ["//visibility:public"],
)
# Common part used by decoder and encoder
cc_library(
name = "woff2common",
srcs = [
"src/table_tags.cc",
"src/variable_length.cc",
"src/woff2_common.cc",
],
hdrs = [
"src/buffer.h",
"src/file.h",
"src/port.h",
"src/round.h",
"src/store_bytes.h",
"src/table_tags.h",
"src/variable_length.h",
"src/woff2_common.h",
],
strip_include_prefix = "src/",
)
# WOFF2 Decoder
cc_library(
name = "woff2dec",
srcs = [
"src/woff2_dec.cc",
"src/woff2_out.cc",
],
hdrs = [
"include/woff2/decode.h",
"include/woff2/output.h",
],
copts = [
"-Wno-unused-variable",
"-Wno-unused-const-variable",
],
strip_include_prefix = "include/",
deps = [
":woff2common",
"@brotli//:brotlidec",
],
)
cc_binary(
name = "woff2_decompress",
srcs = ["src/woff2_decompress.cc"],
deps = [":woff2dec"],
)
# WOFF2 Encoder
cc_library(
name = "woff2enc",
srcs = [
"src/font.cc",
"src/font.h",
"src/glyph.cc",
"src/glyph.h",
"src/normalize.cc",
"src/normalize.h",
"src/transform.cc",
"src/transform.h",
"src/woff2_enc.cc",
],
hdrs = [
"include/woff2/encode.h",
],
copts = [
"-Wno-unused-variable",
"-Wno-unused-const-variable",
"-Wno-sign-compare",
],
strip_include_prefix = "include/",
deps = [
":woff2common",
"@brotli//:brotlienc",
],
)
cc_binary(
name = "woff2_compress",
srcs = ["src/woff2_compress.cc"],
deps = [":woff2enc"],
)
# WOFF2 info
cc_binary(
name = "woff2_info",
srcs = [
"src/font.h",
"src/woff2_info.cc",
],
copts = ["-Wno-sign-compare"],
deps = [":woff2common"],
)
-5
View File
@@ -1,5 +0,0 @@
# Part of the Carbon Language project, under the Apache License v2.0 with LLVM
# Exceptions. See /LICENSE for license information.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
workspace(name = "woff2")
-106
View File
@@ -1,106 +0,0 @@
# Part of the Carbon Language project, under the Apache License v2.0 with LLVM
# Exceptions. See /LICENSE for license information.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
# Rules are adapted from CMakeLists.txt.
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library")
package(
default_visibility = ["//visibility:public"],
)
# Common part used by decoder and encoder
cc_library(
name = "woff2common",
srcs = [
"src/table_tags.cc",
"src/variable_length.cc",
"src/woff2_common.cc",
],
hdrs = [
"src/buffer.h",
"src/file.h",
"src/port.h",
"src/round.h",
"src/store_bytes.h",
"src/table_tags.h",
"src/variable_length.h",
"src/woff2_common.h",
],
strip_include_prefix = "src/",
)
# WOFF2 Decoder
cc_library(
name = "woff2dec",
srcs = [
"src/woff2_dec.cc",
"src/woff2_out.cc",
],
hdrs = [
"include/woff2/decode.h",
"include/woff2/output.h",
],
copts = [
"-Wno-unused-variable",
"-Wno-unused-const-variable",
],
strip_include_prefix = "include/",
deps = [
":woff2common",
"@brotli//:brotlidec",
],
)
cc_binary(
name = "woff2_decompress",
srcs = ["src/woff2_decompress.cc"],
deps = [":woff2dec"],
)
# WOFF2 Encoder
cc_library(
name = "woff2enc",
srcs = [
"src/font.cc",
"src/font.h",
"src/glyph.cc",
"src/glyph.h",
"src/normalize.cc",
"src/normalize.h",
"src/transform.cc",
"src/transform.h",
"src/woff2_enc.cc",
],
hdrs = [
"include/woff2/encode.h",
],
copts = [
"-Wno-unused-variable",
"-Wno-unused-const-variable",
"-Wno-sign-compare",
],
strip_include_prefix = "include/",
deps = [
":woff2common",
"@brotli//:brotlienc",
],
)
cc_binary(
name = "woff2_compress",
srcs = ["src/woff2_compress.cc"],
deps = [":woff2enc"],
)
# WOFF2 info
cc_binary(
name = "woff2_info",
srcs = [
"src/font.h",
"src/woff2_info.cc",
],
copts = ["-Wno-sign-compare"],
deps = [":woff2common"],
)
-19
View File
@@ -1,19 +0,0 @@
Copyright (c) 2013-2017 by the WOFF2 Authors.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-5
View File
@@ -1,5 +0,0 @@
# Part of the Carbon Language project, under the Apache License v2.0 with LLVM
# Exceptions. See /LICENSE for license information.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
workspace(name = "woff2")
@@ -1,37 +0,0 @@
/* Copyright 2014 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Library for converting WOFF2 format font files to their TTF versions. */
#ifndef WOFF2_WOFF2_DEC_H_
#define WOFF2_WOFF2_DEC_H_
#include <woff2/output.h>
#include <cinttypes>
#include <cstddef>
namespace woff2 {
// Compute the size of the final uncompressed font, or 0 on error.
fn ComputeWOFF2FinalSize(data: const uint8_t*, length: size_t) -> size_t;
// Decompresses the font into the target buffer. The result_length should
// be the same as determined by ComputeFinalSize(). Returns true on successful
// decompression.
// DEPRECATED; please prefer the version that takes a WOFF2Out*
fn ConvertWOFF2ToTTF(result: uint8_t*, result_length: size_t,
data: const uint8_t*, length: size_t) -> bool;
// Decompresses the font into out. Returns true on success.
// Works even if WOFF2Header totalSfntSize is wrong.
// Please prefer this API.
fn ConvertWOFF2ToTTF(data: const uint8_t*, length: size_t,
out: WOFF2Out*) -> bool;
} // namespace woff2
#endif // WOFF2_WOFF2_DEC_H_
@@ -1,43 +0,0 @@
/* Copyright 2014 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Library for converting WOFF2 format font files to their TTF versions. */
#ifndef WOFF2_WOFF2_ENC_H_
#define WOFF2_WOFF2_ENC_H_
#include <cinttypes>
#include <cstddef>
#include <string>
namespace woff2 {
struct WOFF2Params {
WOFF2Params() : extended_metadata("")
{}
std::string extended_metadata;
int brotli_quality{11};
bool allow_transforms{true};
};
// Returns an upper bound on the size of the compressed file.
fn MaxWOFF2CompressedSize(data: const uint8_t*, length: size_t) -> size_t;
fn MaxWOFF2CompressedSize(data: const uint8_t*, length: size_t,
extended_metadata: const std::string&) -> size_t;
// Compresses the font into the target buffer. *result_length should be at least
// the value returned by MaxWOFF2CompressedSize(), upon return, it is set to the
// actual compressed size. Returns true on successful compression.
fn ConvertTTFToWOFF2(data: const uint8_t*, length: size_t,
result: uint8_t*, result_length: size_t*) -> bool;
fn ConvertTTFToWOFF2(data: const uint8_t*, length: size_t,
result: uint8_t*, result_length: size_t*,
params: const WOFF2Params&) -> bool;
} // namespace woff2
#endif // WOFF2_WOFF2_ENC_H_
@@ -1,86 +0,0 @@
/* Copyright 2016 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Output buffer for WOFF2 decompression. */
#ifndef WOFF2_WOFF2_OUT_H_
#define WOFF2_WOFF2_OUT_H_
#include <algorithm>
#include <cstring>
#include <memory>
#include <string>
namespace woff2 {
// Suggested max size for output.
let kDefaultMaxSize: const size_t = 30 * 1024 * 1024;
/**
* Output interface for the woff2 decoding.
*
* Writes to arbitrary offsets are supported to facilitate updating offset
* table and checksums after tables are ready. Reading the current size is
* supported so a 'loca' table can be built up while writing glyphs.
*
* By default limits size to kDefaultMaxSize.
*/
class WOFF2Out {
public:
virtual ~WOFF2Out() = default;
// Append n bytes of data from buf.
// Return true if all written, false otherwise.
fn virtual Write(buf: const void*, n: size_t) -> bool = 0;
// Write n bytes of data from buf at offset.
// Return true if all written, false otherwise.
fn virtual Write(buf: const void*, offset: size_t, n: size_t) -> bool = 0;
fn virtual Size() -> size_t = 0;
};
/**
* Expanding memory block for woff2 out. By default limited to kDefaultMaxSize.
*/
class WOFF2StringOut : public WOFF2Out {
public:
// Create a writer that writes its data to buf.
// buf->size() will grow to at most max_size
// buf may be sized (e.g. using EstimateWOFF2FinalSize) or empty.
explicit WOFF2StringOut(buf: std::string*);
fn Write(buf: const void*, n: size_t) -> bool override;
fn Write(buf: const void*, offset: size_t, n: size_t) -> bool override;
fn Size() -> size_t override { return offset_; }
fn MaxSize() -> size_t { return max_size_; }
fn SetMaxSize(max_size: size_t);
private:
std::string* buf_;
size_t max_size_;
size_t offset_;
};
/**
* Fixed memory block for woff2 out.
*/
class WOFF2MemoryOut : public WOFF2Out {
public:
// Create a writer that writes its data to buf.
WOFF2MemoryOut(buf: uint8_t*, buf_size: size_t);
fn Write(buf: const void*, n: size_t) -> bool override;
fn Write(buf: const void*, offset: size_t, n: size_t) -> bool override;
fn Size() -> size_t override { return offset_; }
private:
uint8_t* buf_;
size_t buf_size_;
size_t offset_;
};
} // namespace woff2
#endif // WOFF2_WOFF2_OUT_H_
-165
View File
@@ -1,165 +0,0 @@
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* The parts of ots.h & opentype-sanitiser.h that we need, taken from the
https://code.google.com/p/ots/ project. */
#ifndef WOFF2_BUFFER_H_
#define WOFF2_BUFFER_H_
#if defined(_WIN32)
#include <stdlib.h>
typedef signed char int8_t;
typedef unsigned char uint8_t;
typedef short int16_t;
typedef unsigned short uint16_t;
typedef int int32_t;
typedef unsigned int uint32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
#define ntohl(x) _byteswap_ulong (x)
#define ntohs(x) _byteswap_ushort (x)
#define htonl(x) _byteswap_ulong (x)
#define htons(x) _byteswap_ushort (x)
#else
#include <arpa/inet.h>
#include <cstdint>
#endif
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <limits>
namespace woff2 {
#if defined(_MSC_VER) || !defined(FONT_COMPRESSION_DEBUG)
#define FONT_COMPRESSION_FAILURE() false
#else
#define FONT_COMPRESSION_FAILURE() \
woff2::Failure(__FILE__, __LINE__, __PRETTY_FUNCTION__)
inline bool Failure(const char *f, int l, const char *fn) {
fprintf(stderr, "ERROR at %s:%d (%s)\n", f, l, fn);
fflush(stderr);
return false;
}
#endif
// -----------------------------------------------------------------------------
// Buffer helper class
//
// This class perform some trival buffer operations while checking for
// out-of-bounds errors. As a family they return false if anything is amiss,
// updating the current offset otherwise.
// -----------------------------------------------------------------------------
class Buffer {
public:
Buffer(data: const uint8_t*, len: size_t)
: buffer_(data),
length_(len),
offset_(0) { }
fn Skip(n_bytes: size_t) -> bool {
return Read(nullptr, n_bytes);
}
fn Read(data: uint8_t*, n_bytes: size_t) -> bool {
if (n_bytes > 1024 * 1024 * 1024) {
return FONT_COMPRESSION_FAILURE();
}
if ((offset_ + n_bytes > length_) ||
(offset_ > length_ - n_bytes)) {
return FONT_COMPRESSION_FAILURE();
}
if (data) {
std::memcpy(data, buffer_ + offset_, n_bytes);
}
offset_ += n_bytes;
return true;
}
fn inline ReadU8(value: uint8_t*) -> bool {
if (offset_ + 1 > length_) {
return FONT_COMPRESSION_FAILURE();
}
*value = buffer_[offset_];
++offset_;
return true;
}
fn ReadU16(value: uint16_t*) -> bool {
if (offset_ + 2 > length_) {
return FONT_COMPRESSION_FAILURE();
}
std::memcpy(value, buffer_ + offset_, sizeof(uint16_t));
*value = ntohs(*value);
offset_ += 2;
return true;
}
fn ReadS16(value: int16_t*) -> bool {
return ReadU16(reinterpret_cast<uint16_t*>(value));
}
fn ReadU24(value: uint32_t*) -> bool {
if (offset_ + 3 > length_) {
return FONT_COMPRESSION_FAILURE();
}
*value = static_cast<uint32_t>(buffer_[offset_]) << 16 |
static_cast<uint32_t>(buffer_[offset_ + 1]) << 8 |
static_cast<uint32_t>(buffer_[offset_ + 2]);
offset_ += 3;
return true;
}
fn ReadU32(value: uint32_t*) -> bool {
if (offset_ + 4 > length_) {
return FONT_COMPRESSION_FAILURE();
}
std::memcpy(value, buffer_ + offset_, sizeof(uint32_t));
*value = ntohl(*value);
offset_ += 4;
return true;
}
fn ReadS32(value: int32_t*) -> bool {
return ReadU32(reinterpret_cast<uint32_t*>(value));
}
fn ReadTag(value: uint32_t*) -> bool {
if (offset_ + 4 > length_) {
return FONT_COMPRESSION_FAILURE();
}
std::memcpy(value, buffer_ + offset_, sizeof(uint32_t));
offset_ += 4;
return true;
}
fn ReadR64(value: uint64_t*) -> bool {
if (offset_ + 8 > length_) {
return FONT_COMPRESSION_FAILURE();
}
std::memcpy(value, buffer_ + offset_, sizeof(uint64_t));
offset_ += 8;
return true;
}
[[nodiscard]] fn buffer() const -> const uint8_t * { return buffer_; }
[[nodiscard]] fn offset() const -> size_t { return offset_; }
[[nodiscard]] fn length() const -> size_t { return length_; }
fn set_offset(newoffset: size_t) { offset_ = newoffset; }
private:
const uint8_t * const buffer_;
const size_t length_;
size_t offset_;
};
} // namespace woff2
#endif // WOFF2_BUFFER_H_
@@ -1,13 +0,0 @@
#include <woff2/decode.h>
#include <cstddef>
#include <cstdint>
// Entry point for LibFuzzer.
extern "C" fn LLVMFuzzerTestOneInput(data: const uint8_t*, size: size_t) -> int {
var buf: std::string;
var out: woff2::WOFF2StringOut(&buf);
out.SetMaxSize(30 * 1024 * 1024);
woff2::ConvertWOFF2ToTTF(data, size, &out);
return 0;
}
@@ -1,12 +0,0 @@
#include <string>
#include <woff2/decode.h>
extern "C" fn LLVMFuzzerTestOneInput(data: const uint8_t*, data_size: size_t) -> int {
// Decode using newer entry pattern.
// Same pattern as woff2_decompress.
var output: std::string(std::min(woff2::ComputeWOFF2FinalSize(data, data_size),
woff2::kDefaultMaxSize), 0);
var out: woff2::WOFF2StringOut(&output);
woff2::ConvertWOFF2ToTTF(data, data_size, &out);
return 0;
}
-34
View File
@@ -1,34 +0,0 @@
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* File IO helpers. */
#ifndef WOFF2_FILE_H_
#define WOFF2_FILE_H_
#include <fstream>
#include <iterator>
namespace woff2 {
using std::string;
fn inline GetFileContent(filename: const string&) -> string {
var ifs: std::ifstream(filename.c_str(), std::ios::binary);
return string(
std::istreambuf_iterator<char>(ifs.rdbuf()),
std::istreambuf_iterator<char>());
}
fn inline SetFileContents(filename: const string&, start: string::iterator,
end: string::iterator) {
var ofs: std::ofstream(filename.c_str(), std::ios::binary);
std::copy(start, end, std::ostream_iterator<char>(ofs));
}
} // namespace woff2
#endif // WOFF2_FILE_H_
-105
View File
@@ -1,105 +0,0 @@
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Data model for a font file in sfnt format, reading and writing functions and
accessors for the glyph data. */
#ifndef WOFF2_FONT_H_
#define WOFF2_FONT_H_
#include <cinttypes>
#include <cstddef>
#include <map>
#include <vector>
namespace woff2 {
// Represents an sfnt font file. Only the table directory is parsed, for the
// table data we only store a raw pointer, therefore a font object is valid only
// as long the data from which it was parsed is around.
struct Font {
uint32_t flavor;
uint16_t num_tables;
struct Table {
uint32_t tag;
uint32_t checksum;
uint32_t offset;
uint32_t length;
const uint8_t* data;
// Buffer used to mutate the data before writing out.
std::vector<uint8_t> buffer;
// If we've seen this tag/offset before, pointer to the first time we saw it
// If this is the first time we've seen this table, NULL
// Intended use is to bypass re-processing tables
Font::Table* reuse_of;
uint8_t flag_byte;
// Is this table reused by a TTC
[[nodiscard]] fn IsReused() const -> bool;
};
std::map<uint32_t, Table> tables;
[[nodiscard]] fn OutputOrderedTags() const -> std::vector<uint32_t>;
fn FindTable(tag: uint32_t) -> Table*;
[[nodiscard]] fn FindTable(tag: uint32_t) const -> const Table*;
};
// Accommodates both singular (OTF, TTF) and collection (TTC) fonts
struct FontCollection {
uint32_t flavor;
uint32_t header_version;
// (offset, first use of table*) pairs
std::map<uint32_t, Font::Table*> tables;
std::vector<Font> fonts;
};
// Parses the font from the given data. Returns false on parsing failure or
// buffer overflow. The font is valid only so long the input data pointer is
// valid. Does NOT support collections.
fn ReadFont(data: const uint8_t*, len: size_t, font: Font*) -> bool;
// Parses the font from the given data. Returns false on parsing failure or
// buffer overflow. The font is valid only so long the input data pointer is
// valid. Supports collections.
fn ReadFontCollection(data: const uint8_t*, len: size_t, fonts: FontCollection*) -> bool;
// Returns the file size of the font.
fn FontFileSize(font: const Font&) -> size_t;
fn FontCollectionFileSize(font: const FontCollection&) -> size_t;
// Writes the font into the specified dst buffer. The dst_size should be the
// same as returned by FontFileSize(). Returns false upon buffer overflow (which
// should not happen if dst_size was computed by FontFileSize()).
fn WriteFont(font: const Font&, dst: uint8_t*, dst_size: size_t) -> bool;
// Write the font at a specific offset
fn WriteFont(font: const Font&, offset: size_t*, dst: uint8_t*, dst_size: size_t) -> bool;
fn WriteFontCollection(font_collection: const FontCollection&, dst: uint8_t*,
dst_size: size_t) -> bool;
// Returns the number of glyphs in the font.
// NOTE: Currently this works only for TrueType-flavored fonts, will return
// zero for CFF-flavored fonts.
fn NumGlyphs(font: const Font&) -> int;
// Returns the index format of the font
fn IndexFormat(font: const Font&) -> int;
// Sets *glyph_data and *glyph_size to point to the location of the glyph data
// with the given index. Returns false if the glyph is not found.
fn GetGlyphData(font: const Font&, glyph_index: int,
glyph_data: const uint8_t**, glyph_size: size_t*) -> bool;
// Removes the digital signature (DSIG) table
fn RemoveDigitalSignature(font: Font*) -> bool;
} // namespace woff2
#endif // WOFF2_FONT_H_
-399
View File
@@ -1,399 +0,0 @@
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Font management utilities */
#include "./font.h"
#include <algorithm>
#include "./buffer.h"
#include "./port.h"
#include "./store_bytes.h"
#include "./table_tags.h"
#include "./woff2_common.h"
namespace woff2 {
fn Font::FindTable(tag: uint32_t) -> Font::Table* {
var it: auto = tables.find(tag);
return it == tables.end() ? nullptr : &it->second;
}
fn Font::FindTable(tag: uint32_t) const -> const Font::Table* {
var it: auto = tables.find(tag);
return it == tables.end() ? nullptr : &it->second;
}
fn Font::OutputOrderedTags() const -> std::vector<uint32_t> {
var output_order: std::vector<uint32_t>;
for (const auto& i in tables) {
var table: const Font::Table& = i.second;
// This is a transformed table, we will write it together with the
// original version.
if (table.tag & 0x80808080) {
continue;
}
output_order.push_back(table.tag);
}
// Alphabetize then put loca immediately after glyf
var glyf_loc: auto = std::find(output_order.begin(), output_order.end(),
kGlyfTableTag);
var loca_loc: auto = std::find(output_order.begin(), output_order.end(),
kLocaTableTag);
if (glyf_loc != output_order.end() && loca_loc != output_order.end()) {
output_order.erase(loca_loc);
output_order.insert(std::find(output_order.begin(), output_order.end(),
kGlyfTableTag) + 1, kLocaTableTag);
}
return output_order;
}
fn ReadTrueTypeFont(file: Buffer*, data: const uint8_t*, len: size_t,
font: Font*) -> bool {
// We don't care about the search_range, entry_selector and range_shift
// fields, they will always be computed upon writing the font.
if (!file->ReadU16(&font->num_tables) ||
!file->Skip(6)) {
return FONT_COMPRESSION_FAILURE();
}
var intervals: std::map<uint32_t, uint32_t>;
for (var i: uint16_t = 0; i < font->num_tables; ++i) {
var table: Font::Table;
table.flag_byte = 0;
table.reuse_of = nullptr;
if (!file->ReadU32(&table.tag) ||
!file->ReadU32(&table.checksum) ||
!file->ReadU32(&table.offset) ||
!file->ReadU32(&table.length)) {
return FONT_COMPRESSION_FAILURE();
}
if ((table.offset & 3) != 0 ||
table.length > len ||
len - table.length < table.offset) {
return FONT_COMPRESSION_FAILURE();
}
intervals[table.offset] = table.length;
table.data = data + table.offset;
if (font->tables.find(table.tag) != font->tables.end()) {
return FONT_COMPRESSION_FAILURE();
}
font->tables[table.tag] = table;
}
// Check that tables are non-overlapping.
var last_offset: uint32_t = 12UL + 16UL * font->num_tables;
for (const auto& i in intervals) {
if (i.first < last_offset || i.first + i.second < i.first) {
return FONT_COMPRESSION_FAILURE();
}
last_offset = i.first + i.second;
}
// Sanity check key tables
var head_table: const Font::Table* = font->FindTable(kHeadTableTag);
if (head_table != nullptr && head_table->length < 52) {
return FONT_COMPRESSION_FAILURE();
}
return true;
}
fn ReadCollectionFont(file: Buffer*, data: const uint8_t*, len: size_t,
font: Font*,
all_tables: std::map<uint32_t, Font::Table*>*) -> bool {
if (!file->ReadU32(&font->flavor)) {
return FONT_COMPRESSION_FAILURE();
}
if (!ReadTrueTypeFont(file, data, len, font)) {
return FONT_COMPRESSION_FAILURE();
}
for (auto& entry in font->tables) {
var table: Font::Table& = entry.second;
if (all_tables->find(table.offset) == all_tables->end()) {
(*all_tables)[table.offset] = font->FindTable(table.tag);
} else {
table.reuse_of = (*all_tables)[table.offset];
if (table.tag != table.reuse_of->tag) {
return FONT_COMPRESSION_FAILURE();
}
}
}
return true;
}
fn ReadTrueTypeCollection(file: Buffer*, data: const uint8_t*, len: size_t,
font_collection: FontCollection*) -> bool {
var num_fonts: uint32_t;
if (!file->ReadU32(&font_collection->header_version) ||
!file->ReadU32(&num_fonts)) {
return FONT_COMPRESSION_FAILURE();
}
var offsets: std::vector<uint32_t>;
for (var i: size_t = 0; i < num_fonts; i++) {
var offset: uint32_t;
if (!file->ReadU32(&offset)) {
return FONT_COMPRESSION_FAILURE();
}
offsets.push_back(offset);
}
font_collection->fonts.resize(offsets.size());
var font_it: auto = font_collection->fonts.begin();
var all_tables: std::map<uint32_t, Font::Table*>;
for (const auto offset in offsets) {
file->set_offset(offset);
var font: Font& = *font_it++;
if (!ReadCollectionFont(file, data, len, &font, &all_tables)) {
return FONT_COMPRESSION_FAILURE();
}
}
return true;
}
fn ReadFont(data: const uint8_t*, len: size_t, font: Font*) -> bool {
var file: Buffer(data, len);
if (!file.ReadU32(&font->flavor)) {
return FONT_COMPRESSION_FAILURE();
}
if (font->flavor == kTtcFontFlavor) {
return FONT_COMPRESSION_FAILURE();
}
return ReadTrueTypeFont(&file, data, len, font);
}
fn ReadFontCollection(data: const uint8_t*, len: size_t,
font_collection: FontCollection*) -> bool {
var file: Buffer(data, len);
if (!file.ReadU32(&font_collection->flavor)) {
return FONT_COMPRESSION_FAILURE();
}
if (font_collection->flavor != kTtcFontFlavor) {
font_collection->fonts.resize(1);
var font: Font& = font_collection->fonts[0];
font.flavor = font_collection->flavor;
return ReadTrueTypeFont(&file, data, len, &font);
}
return ReadTrueTypeCollection(&file, data, len, font_collection);
}
fn FontFileSize(font: const Font&) -> size_t {
var max_offset: size_t = 12ULL + 16ULL * font.num_tables;
for (const auto& i in font.tables) {
var table: const Font::Table& = i.second;
var padding_size: size_t = (4 - (table.length & 3)) & 3;
var end_offset: size_t = (padding_size + table.offset) + table.length;
max_offset = std::max(max_offset, end_offset);
}
return max_offset;
}
fn FontCollectionFileSize(font_collection: const FontCollection&) -> size_t {
var max_offset: size_t = 0;
for (auto& font in font_collection.fonts) {
// font file size actually just finds max offset
max_offset = std::max(max_offset, FontFileSize(font));
}
return max_offset;
}
fn WriteFont(font: const Font&, dst: uint8_t*, dst_size: size_t) -> bool {
var offset: size_t = 0;
return WriteFont(font, &offset, dst, dst_size);
}
fn WriteTableRecord(table: const Font::Table*, offset: size_t*, dst: uint8_t*,
dst_size: size_t) -> bool {
if (dst_size < *offset + kSfntEntrySize) {
return FONT_COMPRESSION_FAILURE();
}
if (table->IsReused()) {
table = table->reuse_of;
}
StoreU32(table->tag, offset, dst);
StoreU32(table->checksum, offset, dst);
StoreU32(table->offset, offset, dst);
StoreU32(table->length, offset, dst);
return true;
}
fn WriteTable(table: const Font::Table&, offset: size_t*, dst: uint8_t*,
dst_size: size_t) -> bool {
if (!WriteTableRecord(&table, offset, dst, dst_size)) {
return false;
}
// Write the actual table data if it's the first time we've seen it
if (!table.IsReused()) {
if (table.offset + table.length < table.offset ||
dst_size < table.offset + table.length) {
return FONT_COMPRESSION_FAILURE();
}
memcpy(dst + table.offset, table.data, table.length);
var padding_size: size_t = (4 - (table.length & 3)) & 3;
if (table.offset + table.length + padding_size < padding_size ||
dst_size < table.offset + table.length + padding_size) {
return FONT_COMPRESSION_FAILURE();
}
memset(dst + table.offset + table.length, 0, padding_size);
}
return true;
}
fn WriteFont(font: const Font&, offset: size_t*, dst: uint8_t*,
dst_size: size_t) -> bool {
if (dst_size < 12ULL + 16ULL * font.num_tables) {
return FONT_COMPRESSION_FAILURE();
}
StoreU32(font.flavor, offset, dst);
Store16(font.num_tables, offset, dst);
var max_pow2: uint16_t = font.num_tables ? Log2Floor(font.num_tables) : 0;
var search_range: uint16_t = max_pow2 ? 1 << (max_pow2 + 4) : 0;
var range_shift: uint16_t = (font.num_tables << 4) - search_range;
Store16(search_range, offset, dst);
Store16(max_pow2, offset, dst);
Store16(range_shift, offset, dst);
for (const auto& i in font.tables) {
if (!WriteTable(i.second, offset, dst, dst_size)) {
return false;
}
}
return true;
}
fn WriteFontCollection(font_collection: const FontCollection&, dst: uint8_t*,
dst_size: size_t) -> bool {
var offset: size_t = 0;
// It's simpler if this just a simple sfnt
if (font_collection.flavor != kTtcFontFlavor) {
return WriteFont(font_collection.fonts[0], &offset, dst, dst_size);
}
// Write TTC header
StoreU32(kTtcFontFlavor, &offset, dst);
StoreU32(font_collection.header_version, &offset, dst);
StoreU32(font_collection.fonts.size(), &offset, dst);
// Offset Table, zeroed for now
var offset_table: size_t = offset; // where to write offsets later
for (var i: size_t = 0; i < font_collection.fonts.size(); i++) {
StoreU32(0, &offset, dst);
}
if (font_collection.header_version == 0x00020000) {
StoreU32(0, &offset, dst); // ulDsigTag
StoreU32(0, &offset, dst); // ulDsigLength
StoreU32(0, &offset, dst); // ulDsigOffset
}
// Write fonts and their offsets.
for (const auto & font in font_collection.fonts) {
StoreU32(offset, &offset_table, dst);
if (!WriteFont(font, &offset, dst, dst_size)) {
return false;
}
}
return true;
}
fn NumGlyphs(font: const Font&) -> int {
var head_table: const Font::Table* = font.FindTable(kHeadTableTag);
var loca_table: const Font::Table* = font.FindTable(kLocaTableTag);
if (head_table == nullptr || loca_table == nullptr || head_table->length < 52) {
return 0;
}
var index_fmt: int = IndexFormat(font);
var loca_record_size: int = (index_fmt == 0 ? 2 : 4);
if (loca_table->length < loca_record_size) {
return 0;
}
return (loca_table->length / loca_record_size) - 1;
}
fn IndexFormat(font: const Font&) -> int {
var head_table: const Font::Table* = font.FindTable(kHeadTableTag);
if (head_table == nullptr) {
return 0;
}
return head_table->data[51];
}
fn Font::Table::IsReused() const -> bool {
return this->reuse_of != nullptr;
}
fn GetGlyphData(font: const Font&, glyph_index: int,
glyph_data: const uint8_t**, glyph_size: size_t*) -> bool {
if (glyph_index < 0) {
return FONT_COMPRESSION_FAILURE();
}
var head_table: const Font::Table* = font.FindTable(kHeadTableTag);
var loca_table: const Font::Table* = font.FindTable(kLocaTableTag);
var glyf_table: const Font::Table* = font.FindTable(kGlyfTableTag);
if (head_table == nullptr || loca_table == nullptr || glyf_table == nullptr ||
head_table->length < 52) {
return FONT_COMPRESSION_FAILURE();
}
var index_fmt: int = IndexFormat(font);
var loca_buf: Buffer(loca_table->data, loca_table->length);
if (index_fmt == 0) {
var offset1: uint16_t, var offset2: uint16_t;
if (!loca_buf.Skip(2 * glyph_index) ||
!loca_buf.ReadU16(&offset1) ||
!loca_buf.ReadU16(&offset2) ||
offset2 < offset1 ||
2 * offset2 > glyf_table->length) {
return FONT_COMPRESSION_FAILURE();
}
*glyph_data = glyf_table->data + 2 * offset1;
*glyph_size = 2 * (offset2 - offset1);
} else {
var offset1: uint32_t, var offset2: uint32_t;
if (!loca_buf.Skip(4 * glyph_index) ||
!loca_buf.ReadU32(&offset1) ||
!loca_buf.ReadU32(&offset2) ||
offset2 < offset1 ||
offset2 > glyf_table->length) {
return FONT_COMPRESSION_FAILURE();
}
*glyph_data = glyf_table->data + offset1;
*glyph_size = offset2 - offset1;
}
return true;
}
fn RemoveDigitalSignature(font: Font*) -> bool {
var it: auto =
font->tables.find(kDsigTableTag);
if (it != font->tables.end()) {
font->tables.erase(it);
font->num_tables = font->tables.size();
}
return true;
}
} // namespace woff2
-63
View File
@@ -1,63 +0,0 @@
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Data model and I/O for glyph data within sfnt format files for the purpose of
performing the preprocessing step of the WOFF 2.0 conversion. */
#ifndef WOFF2_GLYPH_H_
#define WOFF2_GLYPH_H_
#include <cinttypes>
#include <cstddef>
#include <vector>
namespace woff2 {
// Represents a parsed simple or composite glyph. The composite glyph data and
// instructions are un-parsed and we keep only pointers to the raw data,
// therefore the glyph is valid only so long the data from which it was parsed
// is around.
class Glyph {
public:
Glyph() {}
// Bounding box.
int16_t x_min;
int16_t x_max;
int16_t y_min;
int16_t y_max;
// Instructions.
uint16_t instructions_size{0};
const uint8_t* instructions_data;
// Data model for simple glyphs.
struct Point {
int x;
int y;
bool on_curve;
};
std::vector<std::vector<Point> > contours;
// Data for composite glyphs.
const uint8_t* composite_data;
uint32_t composite_data_size{0};
bool have_instructions;
};
// Parses the glyph from the given data. Returns false on parsing failure or
// buffer overflow. The glyph is valid only so long the input data pointer is
// valid.
fn ReadGlyph(data: const uint8_t*, len: size_t, glyph: Glyph*) -> bool;
// Stores the glyph into the specified dst buffer. The *dst_size is the buffer
// size on entry and is set to the actual (unpadded) stored size on exit.
// Returns false on buffer overflow.
fn StoreGlyph(glyph: const Glyph&, dst: uint8_t*, dst_size: size_t*) -> bool;
} // namespace woff2
#endif // WOFF2_GLYPH_H_
-375
View File
@@ -1,375 +0,0 @@
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Glyph manipulation */
#include "./glyph.h"
#include <cstdlib>
#include <limits>
#include "./buffer.h"
#include "./store_bytes.h"
namespace woff2 {
let kFLAG_ONCURVE: const int32_t = 1;
let kFLAG_XSHORT: const int32_t = 1 << 1;
let kFLAG_YSHORT: const int32_t = 1 << 2;
let kFLAG_REPEAT: const int32_t = 1 << 3;
let kFLAG_XREPEATSIGN: const int32_t = 1 << 4;
let kFLAG_YREPEATSIGN: const int32_t = 1 << 5;
let kFLAG_ARG_1_AND_2_ARE_WORDS: const int32_t = 1 << 0;
let kFLAG_WE_HAVE_A_SCALE: const int32_t = 1 << 3;
let kFLAG_MORE_COMPONENTS: const int32_t = 1 << 5;
let kFLAG_WE_HAVE_AN_X_AND_Y_SCALE: const int32_t = 1 << 6;
let kFLAG_WE_HAVE_A_TWO_BY_TWO: const int32_t = 1 << 7;
let kFLAG_WE_HAVE_INSTRUCTIONS: const int32_t = 1 << 8;
fn ReadCompositeGlyphData(buffer: Buffer*, glyph: Glyph*) -> bool {
glyph->have_instructions = false;
glyph->composite_data = buffer->buffer() + buffer->offset();
var start_offset: size_t = buffer->offset();
var flags: uint16_t = kFLAG_MORE_COMPONENTS;
while (flags & kFLAG_MORE_COMPONENTS) {
if (!buffer->ReadU16(&flags)) {
return FONT_COMPRESSION_FAILURE();
}
glyph->have_instructions |= (flags & kFLAG_WE_HAVE_INSTRUCTIONS) != 0;
var arg_size: size_t = 2; // glyph index
if (flags & kFLAG_ARG_1_AND_2_ARE_WORDS) {
arg_size += 4;
} else {
arg_size += 2;
}
if (flags & kFLAG_WE_HAVE_A_SCALE) {
arg_size += 2;
} else if (flags & kFLAG_WE_HAVE_AN_X_AND_Y_SCALE) {
arg_size += 4;
} else if (flags & kFLAG_WE_HAVE_A_TWO_BY_TWO) {
arg_size += 8;
}
if (!buffer->Skip(arg_size)) {
return FONT_COMPRESSION_FAILURE();
}
}
if (buffer->offset() - start_offset > std::numeric_limits<uint32_t>::max()) {
return FONT_COMPRESSION_FAILURE();
}
glyph->composite_data_size = buffer->offset() - start_offset;
return true;
}
fn ReadGlyph(data: const uint8_t*, len: size_t, glyph: Glyph*) -> bool {
var buffer: Buffer(data, len);
var num_contours: int16_t;
if (!buffer.ReadS16(&num_contours)) {
return FONT_COMPRESSION_FAILURE();
}
// Read the bounding box.
if (!buffer.ReadS16(&glyph->x_min) ||
!buffer.ReadS16(&glyph->y_min) ||
!buffer.ReadS16(&glyph->x_max) ||
!buffer.ReadS16(&glyph->y_max)) {
return FONT_COMPRESSION_FAILURE();
}
if (num_contours == 0) {
// Empty glyph.
return true;
}
if (num_contours > 0) {
// Simple glyph.
glyph->contours.resize(num_contours);
// Read the number of points per contour.
var last_point_index: uint16_t = 0;
for (var i: int = 0; i < num_contours; ++i) {
var point_index: uint16_t;
if (!buffer.ReadU16(&point_index)) {
return FONT_COMPRESSION_FAILURE();
}
var num_points: uint16_t = point_index - last_point_index + (i == 0 ? 1 : 0);
glyph->contours[i].resize(num_points);
last_point_index = point_index;
}
// Read the instructions.
if (!buffer.ReadU16(&glyph->instructions_size)) {
return FONT_COMPRESSION_FAILURE();
}
glyph->instructions_data = data + buffer.offset();
if (!buffer.Skip(glyph->instructions_size)) {
return FONT_COMPRESSION_FAILURE();
}
// Read the run-length coded flags.
var flags: std::vector<std::vector<uint8_t> >(num_contours);
{
var flag: uint8_t = 0;
var flag_repeat: uint8_t = 0;
for (var i: int = 0; i < num_contours; ++i) {
flags[i].resize(glyph->contours[i].size());
for (var j: size_t = 0; j < glyph->contours[i].size(); ++j) {
if (flag_repeat == 0) {
if (!buffer.ReadU8(&flag)) {
return FONT_COMPRESSION_FAILURE();
}
if (flag & kFLAG_REPEAT) {
if (!buffer.ReadU8(&flag_repeat)) {
return FONT_COMPRESSION_FAILURE();
}
}
} else {
flag_repeat--;
}
flags[i][j] = flag;
glyph->contours[i][j].on_curve = flag & kFLAG_ONCURVE;
}
}
}
// Read the x coordinates.
var prev_x: int = 0;
for (var i: int = 0; i < num_contours; ++i) {
for (var j: size_t = 0; j < glyph->contours[i].size(); ++j) {
var flag: uint8_t = flags[i][j];
if (flag & kFLAG_XSHORT) {
// single byte x-delta coord value
var x_delta: uint8_t;
if (!buffer.ReadU8(&x_delta)) {
return FONT_COMPRESSION_FAILURE();
}
var sign: int = (flag & kFLAG_XREPEATSIGN) ? 1 : -1;
glyph->contours[i][j].x = prev_x + sign * x_delta;
} else {
// double byte x-delta coord value
var x_delta: int16_t = 0;
if (!(flag & kFLAG_XREPEATSIGN)) {
if (!buffer.ReadS16(&x_delta)) {
return FONT_COMPRESSION_FAILURE();
}
}
glyph->contours[i][j].x = prev_x + x_delta;
}
prev_x = glyph->contours[i][j].x;
}
}
// Read the y coordinates.
var prev_y: int = 0;
for (var i: int = 0; i < num_contours; ++i) {
for (var j: size_t = 0; j < glyph->contours[i].size(); ++j) {
var flag: uint8_t = flags[i][j];
if (flag & kFLAG_YSHORT) {
// single byte y-delta coord value
var y_delta: uint8_t;
if (!buffer.ReadU8(&y_delta)) {
return FONT_COMPRESSION_FAILURE();
}
var sign: int = (flag & kFLAG_YREPEATSIGN) ? 1 : -1;
glyph->contours[i][j].y = prev_y + sign * y_delta;
} else {
// double byte y-delta coord value
var y_delta: int16_t = 0;
if (!(flag & kFLAG_YREPEATSIGN)) {
if (!buffer.ReadS16(&y_delta)) {
return FONT_COMPRESSION_FAILURE();
}
}
glyph->contours[i][j].y = prev_y + y_delta;
}
prev_y = glyph->contours[i][j].y;
}
}
} else if (num_contours == -1) {
// Composite glyph.
if (!ReadCompositeGlyphData(&buffer, glyph)) {
return FONT_COMPRESSION_FAILURE();
}
// Read the instructions.
if (glyph->have_instructions) {
if (!buffer.ReadU16(&glyph->instructions_size)) {
return FONT_COMPRESSION_FAILURE();
}
glyph->instructions_data = data + buffer.offset();
if (!buffer.Skip(glyph->instructions_size)) {
return FONT_COMPRESSION_FAILURE();
}
} else {
glyph->instructions_size = 0;
}
} else {
return FONT_COMPRESSION_FAILURE();
}
return true;
}
namespace {
fn StoreBbox(glyph: const Glyph&, offset: size_t*, dst: uint8_t*) {
Store16(glyph.x_min, offset, dst);
Store16(glyph.y_min, offset, dst);
Store16(glyph.x_max, offset, dst);
Store16(glyph.y_max, offset, dst);
}
fn StoreInstructions(glyph: const Glyph&, offset: size_t*, dst: uint8_t*) {
Store16(glyph.instructions_size, offset, dst);
StoreBytes(glyph.instructions_data, glyph.instructions_size, offset, dst);
}
fn StoreEndPtsOfContours(glyph: const Glyph&, offset: size_t*, dst: uint8_t*) -> bool {
var end_point: int = -1;
for (const auto& contour in glyph.contours) {
end_point += contour.size();
if (contour.size() > std::numeric_limits<uint16_t>::max() ||
end_point > std::numeric_limits<uint16_t>::max()) {
return FONT_COMPRESSION_FAILURE();
}
Store16(end_point, offset, dst);
}
return true;
}
fn StorePoints(glyph: const Glyph&, offset: size_t*,
dst: uint8_t*, dst_size: size_t) -> bool {
var last_flag: int = -1;
var repeat_count: int = 0;
var last_x: int = 0;
var last_y: int = 0;
var x_bytes: size_t = 0;
var y_bytes: size_t = 0;
// Store the flags and calculate the total size of the x and y coordinates.
for (const auto& contour in glyph.contours) {
for (const auto& point in contour) {
var flag: int = point.on_curve ? kFLAG_ONCURVE : 0;
var dx: int = point.x - last_x;
var dy: int = point.y - last_y;
if (dx == 0) {
flag |= kFLAG_XREPEATSIGN;
} else if (dx > -256 && dx < 256) {
flag |= kFLAG_XSHORT | (dx > 0 ? kFLAG_XREPEATSIGN : 0);
x_bytes += 1;
} else {
x_bytes += 2;
}
if (dy == 0) {
flag |= kFLAG_YREPEATSIGN;
} else if (dy > -256 && dy < 256) {
flag |= kFLAG_YSHORT | (dy > 0 ? kFLAG_YREPEATSIGN : 0);
y_bytes += 1;
} else {
y_bytes += 2;
}
if (flag == last_flag && repeat_count != 255) {
dst[*offset - 1] |= kFLAG_REPEAT;
repeat_count++;
} else {
if (repeat_count != 0) {
if (*offset >= dst_size) {
return FONT_COMPRESSION_FAILURE();
}
dst[(*offset)++] = repeat_count;
}
if (*offset >= dst_size) {
return FONT_COMPRESSION_FAILURE();
}
dst[(*offset)++] = flag;
repeat_count = 0;
}
last_x = point.x;
last_y = point.y;
last_flag = flag;
}
}
if (repeat_count != 0) {
if (*offset >= dst_size) {
return FONT_COMPRESSION_FAILURE();
}
dst[(*offset)++] = repeat_count;
}
if (*offset + x_bytes + y_bytes > dst_size) {
return FONT_COMPRESSION_FAILURE();
}
// Store the x and y coordinates.
var x_offset: size_t = *offset;
var y_offset: size_t = *offset + x_bytes;
last_x = 0;
last_y = 0;
for (const auto& contour in glyph.contours) {
for (const auto& point in contour) {
var dx: int = point.x - last_x;
var dy: int = point.y - last_y;
if (dx == 0) {
// pass
} else if (dx > -256 && dx < 256) {
dst[x_offset++] = std::abs(dx);
} else {
Store16(dx, &x_offset, dst);
}
if (dy == 0) {
// pass
} else if (dy > -256 && dy < 256) {
dst[y_offset++] = std::abs(dy);
} else {
Store16(dy, &y_offset, dst);
}
last_x += dx;
last_y += dy;
}
}
*offset = y_offset;
return true;
}
} // namespace
fn StoreGlyph(glyph: const Glyph&, dst: uint8_t*, dst_size: size_t*) -> bool {
var offset: size_t = 0;
if (glyph.composite_data_size > 0) {
// Composite glyph.
if (*dst_size < ((10ULL + glyph.composite_data_size) +
((glyph.have_instructions ? 2ULL : 0) +
glyph.instructions_size))) {
return FONT_COMPRESSION_FAILURE();
}
Store16(-1, &offset, dst);
StoreBbox(glyph, &offset, dst);
StoreBytes(glyph.composite_data, glyph.composite_data_size, &offset, dst);
if (glyph.have_instructions) {
StoreInstructions(glyph, &offset, dst);
}
} else if (glyph.contours.size() > 0) {
// Simple glyph.
if (glyph.contours.size() > std::numeric_limits<int16_t>::max()) {
return FONT_COMPRESSION_FAILURE();
}
if (*dst_size < ((12ULL + 2 * glyph.contours.size()) +
glyph.instructions_size)) {
return FONT_COMPRESSION_FAILURE();
}
Store16(glyph.contours.size(), &offset, dst);
StoreBbox(glyph, &offset, dst);
if (!StoreEndPtsOfContours(glyph, &offset, dst)) {
return FONT_COMPRESSION_FAILURE();
}
StoreInstructions(glyph, &offset, dst);
if (!StorePoints(glyph, &offset, dst, *dst_size)) {
return FONT_COMPRESSION_FAILURE();
}
}
*dst_size = offset;
return true;
}
} // namespace woff2
-39
View File
@@ -1,39 +0,0 @@
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Functions for normalizing fonts. Since the WOFF 2.0 decoder creates font
files in normalized form, the WOFF 2.0 conversion is guaranteed to be
lossless (in a bitwise sense) only for normalized font files. */
#ifndef WOFF2_NORMALIZE_H_
#define WOFF2_NORMALIZE_H_
namespace woff2 {
struct Font;
struct FontCollection;
// Changes the offset fields of the table headers so that the data for the
// tables will be written in order of increasing tag values, without any gaps
// other than the 4-byte padding.
fn NormalizeOffsets(font: Font*) -> bool;
// Changes the checksum fields of the table headers and the checksum field of
// the head table so that it matches the current data.
fn FixChecksums(font: Font*) -> bool;
// Parses each of the glyphs in the font and writes them again to the glyf
// table in normalized form, as defined by the StoreGlyph() function. Changes
// the loca table accordingly.
fn NormalizeGlyphs(font: Font*) -> bool;
// Performs all of the normalization steps above.
fn NormalizeFont(font: Font*) -> bool;
fn NormalizeFontCollection(font_collection: FontCollection*) -> bool;
} // namespace woff2
#endif // WOFF2_NORMALIZE_H_
@@ -1,314 +0,0 @@
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Glyph normalization */
#include "./normalize.h"
#include <cinttypes>
#include <cstddef>
#include "./buffer.h"
#include "./font.h"
#include "./glyph.h"
#include "./port.h"
#include "./round.h"
#include "./store_bytes.h"
#include "./table_tags.h"
#include "./woff2_common.h"
namespace woff2 {
namespace {
fn StoreLoca(index_fmt: int, value: uint32_t, offset: size_t*, dst: uint8_t*) {
if (index_fmt == 0) {
Store16(value >> 1, offset, dst);
} else {
StoreU32(value, offset, dst);
}
}
} // namespace
namespace {
fn WriteNormalizedLoca(index_fmt: int, num_glyphs: int, font: Font*) -> bool {
var glyf_table: Font::Table* = font->FindTable(kGlyfTableTag);
var loca_table: Font::Table* = font->FindTable(kLocaTableTag);
var glyph_sz: int = index_fmt == 0 ? 2 : 4;
loca_table->buffer.resize(Round4(num_glyphs + 1) * glyph_sz);
loca_table->length = (num_glyphs + 1) * glyph_sz;
var glyf_dst: uint8_t* = num_glyphs ? &glyf_table->buffer[0] : nullptr;
var loca_dst: uint8_t* = &loca_table->buffer[0];
var glyf_offset: uint32_t = 0;
var loca_offset: size_t = 0;
for (var i: int = 0; i < num_glyphs; ++i) {
StoreLoca(index_fmt, glyf_offset, &loca_offset, loca_dst);
var glyph: Glyph;
var glyph_data: const uint8_t*;
var glyph_size: size_t;
if (!GetGlyphData(*font, i, &glyph_data, &glyph_size) ||
(glyph_size > 0 && !ReadGlyph(glyph_data, glyph_size, &glyph))) {
return FONT_COMPRESSION_FAILURE();
}
var glyf_dst_size: size_t = glyf_table->buffer.size() - glyf_offset;
if (!StoreGlyph(glyph, glyf_dst + glyf_offset, &glyf_dst_size)) {
return FONT_COMPRESSION_FAILURE();
}
glyf_dst_size = Round4(glyf_dst_size);
if (glyf_dst_size > std::numeric_limits<uint32_t>::max() ||
glyf_offset + static_cast<uint32_t>(glyf_dst_size) < glyf_offset ||
(index_fmt == 0 && glyf_offset + glyf_dst_size >= (1UL << 17))) {
return FONT_COMPRESSION_FAILURE();
}
glyf_offset += glyf_dst_size;
}
StoreLoca(index_fmt, glyf_offset, &loca_offset, loca_dst);
glyf_table->buffer.resize(glyf_offset);
glyf_table->data = glyf_offset ? &glyf_table->buffer[0] : nullptr;
glyf_table->length = glyf_offset;
loca_table->data = loca_offset ? &loca_table->buffer[0] : nullptr;
return true;
}
} // namespace
namespace {
fn MakeEditableBuffer(font: Font*, tableTag: int) -> bool {
var table: Font::Table* = font->FindTable(tableTag);
if (table == nullptr) {
return FONT_COMPRESSION_FAILURE();
}
if (table->IsReused()) {
return true;
}
var sz: int = Round4(table->length);
table->buffer.resize(sz);
var buf: uint8_t* = &table->buffer[0];
memcpy(buf, table->data, table->length);
if (PREDICT_FALSE(sz > table->length)) {
memset(buf + table->length, 0, sz - table->length);
}
table->data = buf;
return true;
}
} // namespace
fn NormalizeGlyphs(font: Font*) -> bool {
var head_table: Font::Table* = font->FindTable(kHeadTableTag);
var glyf_table: Font::Table* = font->FindTable(kGlyfTableTag);
var loca_table: Font::Table* = font->FindTable(kLocaTableTag);
if (head_table == nullptr) {
return FONT_COMPRESSION_FAILURE();
}
// If you don't have glyf/loca this transform isn't very interesting
if (loca_table == nullptr && glyf_table == nullptr) {
return true;
}
// It would be best if you didn't have just one of glyf/loca
if ((glyf_table == nullptr) != (loca_table == nullptr)) {
return FONT_COMPRESSION_FAILURE();
}
// Must share neither or both loca & glyf
if (loca_table->IsReused() != glyf_table->IsReused()) {
return FONT_COMPRESSION_FAILURE();
}
if (loca_table->IsReused()) {
return true;
}
var index_fmt: int = head_table->data[51];
var num_glyphs: int = NumGlyphs(*font);
// We need to allocate a bit more than its original length for the normalized
// glyf table, since it can happen that the glyphs in the original table are
// 2-byte aligned, while in the normalized table they are 4-byte aligned.
// That gives a maximum of 2 bytes increase per glyph. However, there is no
// theoretical guarantee that the total size of the flags plus the coordinates
// is the smallest possible in the normalized version, so we have to allow
// some general overhead.
// TODO(user) Figure out some more precise upper bound on the size of
// the overhead.
var max_normalized_glyf_size: size_t = 1.1 * glyf_table->length + 2 * num_glyphs;
glyf_table->buffer.resize(max_normalized_glyf_size);
// if we can't write a loca using short's (index_fmt 0)
// try again using longs (index_fmt 1)
if (!WriteNormalizedLoca(index_fmt, num_glyphs, font)) {
if (index_fmt != 0) {
return FONT_COMPRESSION_FAILURE();
}
// Rewrite loca with 4-byte entries & update head to match
index_fmt = 1;
if (!WriteNormalizedLoca(index_fmt, num_glyphs, font)) {
return FONT_COMPRESSION_FAILURE();
}
head_table->buffer[51] = 1;
}
return true;
}
fn NormalizeOffsets(font: Font*) -> bool {
var offset: uint32_t = 12 + 16 * font->num_tables;
for (auto tag in font->OutputOrderedTags()) {
var table: auto& = font->tables[tag];
table.offset = offset;
offset += Round4(table.length);
}
return true;
}
namespace {
fn ComputeHeaderChecksum(font: const Font&) -> uint32_t {
var checksum: uint32_t = font.flavor;
var max_pow2: uint16_t = font.num_tables ? Log2Floor(font.num_tables) : 0;
var search_range: uint16_t = max_pow2 ? 1 << (max_pow2 + 4) : 0;
var range_shift: uint16_t = (font.num_tables << 4) - search_range;
checksum += (font.num_tables << 16 | search_range);
checksum += (max_pow2 << 16 | range_shift);
for (const auto& i in font.tables) {
var table: const Font::Table* = &i.second;
if (table->IsReused()) {
table = table->reuse_of;
}
checksum += table->tag;
checksum += table->checksum;
checksum += table->offset;
checksum += table->length;
}
return checksum;
}
} // namespace
fn FixChecksums(font: Font*) -> bool {
var head_table: Font::Table* = font->FindTable(kHeadTableTag);
if (head_table == nullptr) {
return FONT_COMPRESSION_FAILURE();
}
if (head_table->reuse_of != nullptr) {
head_table = head_table->reuse_of;
}
if (head_table->length < 12) {
return FONT_COMPRESSION_FAILURE();
}
var head_buf: uint8_t* = &head_table->buffer[0];
var offset: size_t = 8;
StoreU32(0, &offset, head_buf);
var file_checksum: uint32_t = 0;
var head_checksum: uint32_t = 0;
for (auto& i in font->tables) {
var table: Font::Table* = &i.second;
if (table->IsReused()) {
table = table->reuse_of;
}
table->checksum = ComputeULongSum(table->data, table->length);
file_checksum += table->checksum;
if (table->tag == kHeadTableTag) {
head_checksum = table->checksum;
}
}
file_checksum += ComputeHeaderChecksum(*font);
offset = 8;
StoreU32(0xb1b0afba - file_checksum, &offset, head_buf);
return true;
}
namespace {
fn MarkTransformed(font: Font*) -> bool {
var head_table: Font::Table* = font->FindTable(kHeadTableTag);
if (head_table == nullptr) {
return FONT_COMPRESSION_FAILURE();
}
if (head_table->reuse_of != nullptr) {
head_table = head_table->reuse_of;
}
if (head_table->length < 17) {
return FONT_COMPRESSION_FAILURE();
}
// set bit 11 of head table 'flags' to indicate that font has undergone
// lossless modifying transform
var head_flags: int = head_table->data[16];
head_table->buffer[16] = head_flags | 0x08;
return true;
}
} // namespace
fn NormalizeWithoutFixingChecksums(font: Font*) -> bool {
return (MakeEditableBuffer(font, kHeadTableTag) &&
RemoveDigitalSignature(font) &&
MarkTransformed(font) &&
NormalizeGlyphs(font) &&
NormalizeOffsets(font));
}
fn NormalizeFont(font: Font*) -> bool {
return (NormalizeWithoutFixingChecksums(font) &&
FixChecksums(font));
}
fn NormalizeFontCollection(font_collection: FontCollection*) -> bool {
if (font_collection->fonts.size() == 1) {
return NormalizeFont(&font_collection->fonts[0]);
}
var offset: uint32_t = CollectionHeaderSize(font_collection->header_version,
font_collection->fonts.size());
for (auto& font in font_collection->fonts) {
if (!NormalizeWithoutFixingChecksums(&font)) {
#ifdef FONT_COMPRESSION_BIN
fprintf(stderr, "Font normalization failed.\n");
#endif
return FONT_COMPRESSION_FAILURE();
}
offset += kSfntHeaderSize + kSfntEntrySize * font.num_tables;
}
// Start table offsets after TTC Header and Sfnt Headers
for (auto& font in font_collection->fonts) {
for (auto tag in font.OutputOrderedTags()) {
var table: Font::Table& = font.tables[tag];
if (table.IsReused()) {
table.offset = table.reuse_of->offset;
} else {
table.offset = offset;
offset += Round4(table.length);
}
}
}
// Now we can fix the checksums
for (auto& font in font_collection->fonts) {
if (!FixChecksums(&font)) {
#ifdef FONT_COMPRESSION_BIN
fprintf(stderr, "Failed to fix checksums\n");
#endif
return FONT_COMPRESSION_FAILURE();
}
}
return true;
}
} // namespace woff2
-66
View File
@@ -1,66 +0,0 @@
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Helper function for bit twiddling and macros for branch prediction. */
#ifndef WOFF2_PORT_H_
#define WOFF2_PORT_H_
#include <cassert>
namespace woff2 {
using uint32 = unsigned int;
fn inline Log2Floor(n: uint32) -> int {
#if defined(__GNUC__)
return n == 0 ? -1 : 31 ^ __builtin_clz(n);
#else
if (n == 0)
return -1;
int log = 0;
uint32 value = n;
for (int i = 4; i >= 0; --i) {
int shift = (1 << i);
uint32 x = value >> shift;
if (x != 0) {
value = x;
log += shift;
}
}
assert(value == 1);
return log;
#endif
}
} // namespace woff2
/* Compatibility with non-clang compilers. */
#ifndef __has_builtin
#define __has_builtin(x) 0
#endif
#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ > 95) || \
(defined(__llvm__) && __has_builtin(__builtin_expect))
#define PREDICT_FALSE(x) (__builtin_expect(x, 0))
#define PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
#else
#define PREDICT_FALSE(x) (x)
#define PREDICT_TRUE(x) (x)
#endif
#if (defined(__ARM_ARCH) && (__ARM_ARCH == 7)) || \
(defined(M_ARM) && (M_ARM == 7)) || \
defined(__aarch64__) || defined(__ARM64_ARCH_8__) || defined(__i386) || \
defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64)
#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
#define WOFF_LITTLE_ENDIAN
#elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
#define WOFF_BIG_ENDIAN
#endif /* endianness */
#endif /* CPU whitelist */
#endif // WOFF2_PORT_H_
-27
View File
@@ -1,27 +0,0 @@
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Helper for rounding */
#ifndef WOFF2_ROUND_H_
#define WOFF2_ROUND_H_
#include <limits>
namespace woff2 {
// 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> fn Round4(value: T) -> T {
if (std::numeric_limits<T>::max() - value < 3) {
return value;
}
return (value + 3) & ~3;
}
} // namespace woff2
#endif // WOFF2_ROUND_H_
@@ -1,71 +0,0 @@
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Helper functions for storing integer values into byte streams.
No bounds checking is performed, that is the responsibility of the caller. */
#ifndef WOFF2_STORE_BYTES_H_
#define WOFF2_STORE_BYTES_H_
#include <cinttypes>
#include <cstddef>
#include <cstring>
#include "./port.h"
namespace woff2 {
fn inline StoreU32(dst: uint8_t*, offset: size_t, x: uint32_t) -> size_t {
dst[offset] = x >> 24;
dst[offset + 1] = x >> 16;
dst[offset + 2] = x >> 8;
dst[offset + 3] = x;
return offset + 4;
}
fn inline Store16(dst: uint8_t*, offset: size_t, x: int) -> size_t {
#if defined(WOFF_LITTLE_ENDIAN)
*reinterpret_cast<uint16_t*>(dst + offset) =
((x & 0xFF) << 8) | ((x & 0xFF00) >> 8);
#elif defined(WOFF_BIG_ENDIAN)
*reinterpret_cast<uint16_t*>(dst + offset) = static_cast<uint16_t>(x);
#else
dst[offset] = x >> 8;
dst[offset + 1] = x;
#endif
return offset + 2;
}
fn inline StoreU32(val: uint32_t, offset: size_t*, dst: uint8_t*) {
dst[(*offset)++] = val >> 24;
dst[(*offset)++] = val >> 16;
dst[(*offset)++] = val >> 8;
dst[(*offset)++] = val;
}
fn inline Store16(val: int, offset: size_t*, dst: uint8_t*) {
#if defined(WOFF_LITTLE_ENDIAN)
*reinterpret_cast<uint16_t*>(dst + *offset) =
((val & 0xFF) << 8) | ((val & 0xFF00) >> 8);
*offset += 2;
#elif defined(WOFF_BIG_ENDIAN)
*reinterpret_cast<uint16_t*>(dst + *offset) = static_cast<uint16_t>(val);
*offset += 2;
#else
dst[(*offset)++] = val >> 8;
dst[(*offset)++] = val;
#endif
}
fn inline StoreBytes(data: const uint8_t*, len: size_t,
offset: size_t*, dst: uint8_t*) {
memcpy(&dst[*offset], data, len);
*offset += len;
}
} // namespace woff2
#endif // WOFF2_STORE_BYTES_H_
-30
View File
@@ -1,30 +0,0 @@
/* Copyright 2014 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Font table tags */
#ifndef WOFF2_TABLE_TAGS_H_
#define WOFF2_TABLE_TAGS_H_
#include <cinttypes>
namespace woff2 {
// Tags of popular tables.
let kGlyfTableTag: const uint32_t = 0x676c7966;
let kHeadTableTag: const uint32_t = 0x68656164;
let kLocaTableTag: const uint32_t = 0x6c6f6361;
let kDsigTableTag: const uint32_t = 0x44534947;
let kCffTableTag: const uint32_t = 0x43464620;
let kHmtxTableTag: const uint32_t = 0x686d7478;
let kHheaTableTag: const uint32_t = 0x68686561;
let kMaxpTableTag: const uint32_t = 0x6d617870;
let kKnownTags: const uint32_t[];
} // namespace woff2
#endif // WOFF2_TABLE_TAGS_H_
@@ -1,82 +0,0 @@
/* Copyright 2014 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Font table tags */
#include "./table_tags.h"
namespace woff2 {
// Note that the byte order is big-endian, not the same as ots.cc
#define TAG(a, b, c, d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
let kKnownTags: const uint32_t[63] = {
TAG('c', 'm', 'a', 'p'), // 0
TAG('h', 'e', 'a', 'd'), // 1
TAG('h', 'h', 'e', 'a'), // 2
TAG('h', 'm', 't', 'x'), // 3
TAG('m', 'a', 'x', 'p'), // 4
TAG('n', 'a', 'm', 'e'), // 5
TAG('O', 'S', '/', '2'), // 6
TAG('p', 'o', 's', 't'), // 7
TAG('c', 'v', 't', ' '), // 8
TAG('f', 'p', 'g', 'm'), // 9
TAG('g', 'l', 'y', 'f'), // 10
TAG('l', 'o', 'c', 'a'), // 11
TAG('p', 'r', 'e', 'p'), // 12
TAG('C', 'F', 'F', ' '), // 13
TAG('V', 'O', 'R', 'G'), // 14
TAG('E', 'B', 'D', 'T'), // 15
TAG('E', 'B', 'L', 'C'), // 16
TAG('g', 'a', 's', 'p'), // 17
TAG('h', 'd', 'm', 'x'), // 18
TAG('k', 'e', 'r', 'n'), // 19
TAG('L', 'T', 'S', 'H'), // 20
TAG('P', 'C', 'L', 'T'), // 21
TAG('V', 'D', 'M', 'X'), // 22
TAG('v', 'h', 'e', 'a'), // 23
TAG('v', 'm', 't', 'x'), // 24
TAG('B', 'A', 'S', 'E'), // 25
TAG('G', 'D', 'E', 'F'), // 26
TAG('G', 'P', 'O', 'S'), // 27
TAG('G', 'S', 'U', 'B'), // 28
TAG('E', 'B', 'S', 'C'), // 29
TAG('J', 'S', 'T', 'F'), // 30
TAG('M', 'A', 'T', 'H'), // 31
TAG('C', 'B', 'D', 'T'), // 32
TAG('C', 'B', 'L', 'C'), // 33
TAG('C', 'O', 'L', 'R'), // 34
TAG('C', 'P', 'A', 'L'), // 35
TAG('S', 'V', 'G', ' '), // 36
TAG('s', 'b', 'i', 'x'), // 37
TAG('a', 'c', 'n', 't'), // 38
TAG('a', 'v', 'a', 'r'), // 39
TAG('b', 'd', 'a', 't'), // 40
TAG('b', 'l', 'o', 'c'), // 41
TAG('b', 's', 'l', 'n'), // 42
TAG('c', 'v', 'a', 'r'), // 43
TAG('f', 'd', 's', 'c'), // 44
TAG('f', 'e', 'a', 't'), // 45
TAG('f', 'm', 't', 'x'), // 46
TAG('f', 'v', 'a', 'r'), // 47
TAG('g', 'v', 'a', 'r'), // 48
TAG('h', 's', 't', 'y'), // 49
TAG('j', 'u', 's', 't'), // 50
TAG('l', 'c', 'a', 'r'), // 51
TAG('m', 'o', 'r', 't'), // 52
TAG('m', 'o', 'r', 'x'), // 53
TAG('o', 'p', 'b', 'd'), // 54
TAG('p', 'r', 'o', 'p'), // 55
TAG('t', 'r', 'a', 'k'), // 56
TAG('Z', 'a', 'p', 'f'), // 57
TAG('S', 'i', 'l', 'f'), // 58
TAG('G', 'l', 'a', 't'), // 59
TAG('G', 'l', 'o', 'c'), // 60
TAG('F', 'e', 'a', 't'), // 61
TAG('S', 'i', 'l', 'l'), // 62
};
} // namespace woff2
-26
View File
@@ -1,26 +0,0 @@
/* Copyright 2014 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Library for preprocessing fonts as part of the WOFF 2.0 conversion. */
#ifndef WOFF2_TRANSFORM_H_
#define WOFF2_TRANSFORM_H_
#include "./font.h"
namespace woff2 {
// Adds the transformed versions of the glyf and loca tables to the font. The
// transformed loca table has zero length. The tag of the transformed tables is
// derived from the original tag by flipping the MSBs of every byte.
fn TransformGlyfAndLocaTables(font: Font*) -> bool;
// Apply transformation to hmtx table if applicable for this font.
fn TransformHmtxTable(font: Font*) -> bool;
} // namespace woff2
#endif // WOFF2_TRANSFORM_H_
@@ -1,421 +0,0 @@
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Library for preprocessing fonts as part of the WOFF 2.0 conversion. */
#include "./transform.h"
#include <complex> // for std::abs
#include "./buffer.h"
#include "./font.h"
#include "./glyph.h"
#include "./table_tags.h"
#include "./variable_length.h"
namespace woff2 {
namespace {
let FLAG_ARG_1_AND_2_ARE_WORDS: const int = 1 << 0;
let FLAG_WE_HAVE_INSTRUCTIONS: const int = 1 << 8;
fn WriteBytes(out: std::vector<uint8_t>*, data: const uint8_t*, len: size_t) {
if (len == 0) { return;
}
var offset: size_t = out->size();
out->resize(offset + len);
memcpy(&(*out)[offset], data, len);
}
fn WriteBytes(out: std::vector<uint8_t>*, in: const std::vector<uint8_t>&) {
for (unsigned char i in in) {
out->push_back(i);
}
}
fn WriteUShort(out: std::vector<uint8_t>*, value: int) {
out->push_back(value >> 8);
out->push_back(value & 255);
}
fn WriteLong(out: std::vector<uint8_t>*, value: int) {
out->push_back((value >> 24) & 255);
out->push_back((value >> 16) & 255);
out->push_back((value >> 8) & 255);
out->push_back(value & 255);
}
// Glyf table preprocessing, based on
// GlyfEncoder.java
class GlyfEncoder {
public:
explicit GlyfEncoder(num_glyphs: int)
: n_glyphs_(num_glyphs) {
bbox_bitmap_.resize(((num_glyphs + 31) >> 5) << 2);
}
fn Encode(glyph_id: int, glyph: const Glyph&) -> bool {
if (glyph.composite_data_size > 0) {
WriteCompositeGlyph(glyph_id, glyph);
} else if (glyph.contours.size() > 0) {
WriteSimpleGlyph(glyph_id, glyph);
} else {
WriteUShort(&n_contour_stream_, 0);
}
return true;
}
fn GetTransformedGlyfBytes(result: std::vector<uint8_t>*) {
WriteLong(result, 0); // version
WriteUShort(result, n_glyphs_);
WriteUShort(result, 0); // index_format, will be set later
WriteLong(result, n_contour_stream_.size());
WriteLong(result, n_points_stream_.size());
WriteLong(result, flag_byte_stream_.size());
WriteLong(result, glyph_stream_.size());
WriteLong(result, composite_stream_.size());
WriteLong(result, bbox_bitmap_.size() + bbox_stream_.size());
WriteLong(result, instruction_stream_.size());
WriteBytes(result, n_contour_stream_);
WriteBytes(result, n_points_stream_);
WriteBytes(result, flag_byte_stream_);
WriteBytes(result, glyph_stream_);
WriteBytes(result, composite_stream_);
WriteBytes(result, bbox_bitmap_);
WriteBytes(result, bbox_stream_);
WriteBytes(result, instruction_stream_);
}
private:
fn WriteInstructions(glyph: const Glyph&) {
Write255UShort(&glyph_stream_, glyph.instructions_size);
WriteBytes(&instruction_stream_,
glyph.instructions_data, glyph.instructions_size);
}
fn ShouldWriteSimpleGlyphBbox(glyph: const Glyph&) -> bool {
if (glyph.contours.empty() || glyph.contours[0].empty()) {
return glyph.x_min || glyph.y_min || glyph.x_max || glyph.y_max;
}
var x_min: int16_t = glyph.contours[0][0].x;
var y_min: int16_t = glyph.contours[0][0].y;
var x_max: int16_t = x_min;
var y_max: int16_t = y_min;
for (const auto& contour in glyph.contours) {
for (const auto& point in contour) {
if (point.x < x_min) { x_min = point.x;
}
if (point.x > x_max) { x_max = point.x;
}
if (point.y < y_min) { y_min = point.y;
}
if (point.y > y_max) { y_max = point.y;
}
}
}
if (glyph.x_min != x_min) {
return true;
}
if (glyph.y_min != y_min) {
return true;
}
if (glyph.x_max != x_max) {
return true;
}
if (glyph.y_max != y_max) {
return true;
}
return false;
}
fn WriteSimpleGlyph(glyph_id: int, glyph: const Glyph&) {
var num_contours: int = glyph.contours.size();
WriteUShort(&n_contour_stream_, num_contours);
if (ShouldWriteSimpleGlyphBbox(glyph)) {
WriteBbox(glyph_id, glyph);
}
for (var i: int = 0; i < num_contours; i++) {
Write255UShort(&n_points_stream_, glyph.contours[i].size());
}
var lastX: int = 0;
var lastY: int = 0;
for (var i: int = 0; i < num_contours; i++) {
var num_points: int = glyph.contours[i].size();
for (var j: int = 0; j < num_points; j++) {
var x: int = glyph.contours[i][j].x;
var y: int = glyph.contours[i][j].y;
var dx: int = x - lastX;
var dy: int = y - lastY;
WriteTriplet(glyph.contours[i][j].on_curve, dx, dy);
lastX = x;
lastY = y;
}
}
if (num_contours > 0) {
WriteInstructions(glyph);
}
}
fn WriteCompositeGlyph(glyph_id: int, glyph: const Glyph&) {
WriteUShort(&n_contour_stream_, -1);
WriteBbox(glyph_id, glyph);
WriteBytes(&composite_stream_,
glyph.composite_data,
glyph.composite_data_size);
if (glyph.have_instructions) {
WriteInstructions(glyph);
}
}
fn WriteBbox(glyph_id: int, glyph: const Glyph&) {
bbox_bitmap_[glyph_id >> 3] |= 0x80 >> (glyph_id & 7);
WriteUShort(&bbox_stream_, glyph.x_min);
WriteUShort(&bbox_stream_, glyph.y_min);
WriteUShort(&bbox_stream_, glyph.x_max);
WriteUShort(&bbox_stream_, glyph.y_max);
}
fn WriteTriplet(on_curve: bool, x: int, y: int) {
var abs_x: int = std::abs(x);
var abs_y: int = std::abs(y);
var on_curve_bit: int = on_curve ? 0 : 128;
var x_sign_bit: int = (x < 0) ? 0 : 1;
var y_sign_bit: int = (y < 0) ? 0 : 1;
var xy_sign_bits: int = x_sign_bit + 2 * y_sign_bit;
if (x == 0 && abs_y < 1280) {
flag_byte_stream_.push_back(on_curve_bit +
((abs_y & 0xf00) >> 7) + y_sign_bit);
glyph_stream_.push_back(abs_y & 0xff);
} else if (y == 0 && abs_x < 1280) {
flag_byte_stream_.push_back(on_curve_bit + 10 +
((abs_x & 0xf00) >> 7) + x_sign_bit);
glyph_stream_.push_back(abs_x & 0xff);
} else if (abs_x < 65 && abs_y < 65) {
flag_byte_stream_.push_back(on_curve_bit + 20 +
((abs_x - 1) & 0x30) +
(((abs_y - 1) & 0x30) >> 2) +
xy_sign_bits);
glyph_stream_.push_back((((abs_x - 1) & 0xf) << 4) | ((abs_y - 1) & 0xf));
} else if (abs_x < 769 && abs_y < 769) {
flag_byte_stream_.push_back(on_curve_bit + 84 +
12 * (((abs_x - 1) & 0x300) >> 8) +
(((abs_y - 1) & 0x300) >> 6) + xy_sign_bits);
glyph_stream_.push_back((abs_x - 1) & 0xff);
glyph_stream_.push_back((abs_y - 1) & 0xff);
} else if (abs_x < 4096 && abs_y < 4096) {
flag_byte_stream_.push_back(on_curve_bit + 120 + xy_sign_bits);
glyph_stream_.push_back(abs_x >> 4);
glyph_stream_.push_back(((abs_x & 0xf) << 4) | (abs_y >> 8));
glyph_stream_.push_back(abs_y & 0xff);
} else {
flag_byte_stream_.push_back(on_curve_bit + 124 + xy_sign_bits);
glyph_stream_.push_back(abs_x >> 8);
glyph_stream_.push_back(abs_x & 0xff);
glyph_stream_.push_back(abs_y >> 8);
glyph_stream_.push_back(abs_y & 0xff);
}
}
std::vector<uint8_t> n_contour_stream_;
std::vector<uint8_t> n_points_stream_;
std::vector<uint8_t> flag_byte_stream_;
std::vector<uint8_t> composite_stream_;
std::vector<uint8_t> bbox_bitmap_;
std::vector<uint8_t> bbox_stream_;
std::vector<uint8_t> glyph_stream_;
std::vector<uint8_t> instruction_stream_;
int n_glyphs_;
};
} // namespace
fn TransformGlyfAndLocaTables(font: Font*) -> bool {
// no transform for CFF
var glyf_table: const Font::Table* = font->FindTable(kGlyfTableTag);
var loca_table: const Font::Table* = font->FindTable(kLocaTableTag);
// If you don't have glyf/loca this transform isn't very interesting
if (loca_table == nullptr && glyf_table == nullptr) {
return true;
}
// It would be best if you didn't have just one of glyf/loca
if ((glyf_table == nullptr) != (loca_table == nullptr)) {
return FONT_COMPRESSION_FAILURE();
}
// Must share neither or both loca & glyf
if (loca_table->IsReused() != glyf_table->IsReused()) {
return FONT_COMPRESSION_FAILURE();
}
if (loca_table->IsReused()) {
return true;
}
var transformed_glyf: Font::Table* = &font->tables[kGlyfTableTag ^ 0x80808080];
var transformed_loca: Font::Table* = &font->tables[kLocaTableTag ^ 0x80808080];
var num_glyphs: int = NumGlyphs(*font);
var encoder: GlyfEncoder(num_glyphs);
for (var i: int = 0; i < num_glyphs; ++i) {
var glyph: Glyph;
var glyph_data: const uint8_t*;
var glyph_size: size_t;
if (!GetGlyphData(*font, i, &glyph_data, &glyph_size) ||
(glyph_size > 0 && !ReadGlyph(glyph_data, glyph_size, &glyph))) {
return FONT_COMPRESSION_FAILURE();
}
encoder.Encode(i, glyph);
}
encoder.GetTransformedGlyfBytes(&transformed_glyf->buffer);
var head_table: const Font::Table* = font->FindTable(kHeadTableTag);
if (head_table == nullptr || head_table->length < 52) {
return FONT_COMPRESSION_FAILURE();
}
transformed_glyf->buffer[7] = head_table->data[51]; // index_format
transformed_glyf->tag = kGlyfTableTag ^ 0x80808080;
transformed_glyf->length = transformed_glyf->buffer.size();
transformed_glyf->data = transformed_glyf->buffer.data();
transformed_loca->tag = kLocaTableTag ^ 0x80808080;
transformed_loca->length = 0;
transformed_loca->data = nullptr;
return true;
}
// See https://www.microsoft.com/typography/otspec/hmtx.htm
// See WOFF2 spec, 5.4. Transformed hmtx table format
fn TransformHmtxTable(font: Font*) -> bool {
var glyf_table: const Font::Table* = font->FindTable(kGlyfTableTag);
var hmtx_table: const Font::Table* = font->FindTable(kHmtxTableTag);
var hhea_table: const Font::Table* = font->FindTable(kHheaTableTag);
// If you don't have hmtx or a glyf not much is going to happen here
if (hmtx_table == nullptr || glyf_table == nullptr) {
return true;
}
// hmtx without hhea doesn't make sense
if (hhea_table == nullptr) {
return FONT_COMPRESSION_FAILURE();
}
// Skip 34 to reach 'hhea' numberOfHMetrics
var hhea_buf: Buffer(hhea_table->data, hhea_table->length);
var num_hmetrics: uint16_t;
if (!hhea_buf.Skip(34) || !hhea_buf.ReadU16(&num_hmetrics)) {
return FONT_COMPRESSION_FAILURE();
}
// Must have at least one hMetric
if (num_hmetrics < 1) {
return FONT_COMPRESSION_FAILURE();
}
var num_glyphs: int = NumGlyphs(*font);
// Most fonts can be transformed; assume it's a go until proven otherwise
var advance_widths: std::vector<uint16_t>;
var proportional_lsbs: std::vector<int16_t>;
var monospace_lsbs: std::vector<int16_t>;
var remove_proportional_lsb: bool = true;
var remove_monospace_lsb: bool = (num_glyphs - num_hmetrics) > 0;
var hmtx_buf: Buffer(hmtx_table->data, hmtx_table->length);
for (var i: int = 0; i < num_glyphs; i++) {
var glyph: Glyph;
var glyph_data: const uint8_t*;
var glyph_size: size_t;
if (!GetGlyphData(*font, i, &glyph_data, &glyph_size) ||
(glyph_size > 0 && !ReadGlyph(glyph_data, glyph_size, &glyph))) {
return FONT_COMPRESSION_FAILURE();
}
var advance_width: uint16_t = 0;
var lsb: int16_t = 0;
if (i < num_hmetrics) {
// [0, num_hmetrics) are proportional hMetrics
if (!hmtx_buf.ReadU16(&advance_width)) {
return FONT_COMPRESSION_FAILURE();
}
if (!hmtx_buf.ReadS16(&lsb)) {
return FONT_COMPRESSION_FAILURE();
}
if (glyph_size > 0 && glyph.x_min != lsb) {
remove_proportional_lsb = false;
}
advance_widths.push_back(advance_width);
proportional_lsbs.push_back(lsb);
} else {
// [num_hmetrics, num_glyphs) are monospace leftSideBearing's
if (!hmtx_buf.ReadS16(&lsb)) {
return FONT_COMPRESSION_FAILURE();
}
if (glyph_size > 0 && glyph.x_min != lsb) {
remove_monospace_lsb = false;
}
monospace_lsbs.push_back(lsb);
}
// If we know we can't optimize, bail out completely
if (!remove_proportional_lsb && !remove_monospace_lsb) {
return true;
}
}
var transformed_hmtx: Font::Table* = &font->tables[kHmtxTableTag ^ 0x80808080];
var flags: uint8_t = 0;
var transformed_size: size_t = 1 + 2 * advance_widths.size();
if (remove_proportional_lsb) {
flags |= 1;
} else {
transformed_size += 2 * proportional_lsbs.size();
}
if (remove_monospace_lsb) {
flags |= 1 << 1;
} else {
transformed_size += 2 * monospace_lsbs.size();
}
transformed_hmtx->buffer.reserve(transformed_size);
var out: std::vector<uint8_t>* = &transformed_hmtx->buffer;
WriteBytes(out, &flags, 1);
for (uint16_t advance_width in advance_widths) {
WriteUShort(out, advance_width);
}
if (!remove_proportional_lsb) {
for (int16_t lsb in proportional_lsbs) {
WriteUShort(out, lsb);
}
}
if (!remove_monospace_lsb) {
for (int16_t lsb in monospace_lsbs) {
WriteUShort(out, lsb);
}
}
transformed_hmtx->tag = kHmtxTableTag ^ 0x80808080;
transformed_hmtx->flag_byte = 1 << 6;
transformed_hmtx->length = transformed_hmtx->buffer.size();
transformed_hmtx->data = transformed_hmtx->buffer.data();
return true;
}
} // namespace woff2
@@ -1,31 +0,0 @@
/* Copyright 2015 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Helper functions for woff2 variable length types: 255UInt16 and UIntBase128 */
#ifndef WOFF2_VARIABLE_LENGTH_H_
#define WOFF2_VARIABLE_LENGTH_H_
#include <cinttypes>
#include <vector>
#include "./buffer.h"
namespace woff2 {
fn Size255UShort(value: uint16_t) -> size_t;
fn Read255UShort(buf: Buffer*, value: unsigned int*) -> bool;
fn Write255UShort(out: std::vector<uint8_t>*, value: int);
fn Store255UShort(val: int, offset: size_t*, dst: uint8_t*);
fn Base128Size(n: size_t) -> size_t;
fn ReadBase128(buf: Buffer*, value: uint32_t*) -> bool;
fn StoreBase128(len: size_t, offset: size_t*, dst: uint8_t*);
} // namespace woff2
#endif // WOFF2_VARIABLE_LENGTH_H_
@@ -1,130 +0,0 @@
/* Copyright 2015 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Helper functions for woff2 variable length types: 255UInt16 and UIntBase128 */
#include "./variable_length.h"
namespace woff2 {
fn Size255UShort(value: uint16_t) -> size_t {
var result: size_t = 3;
if (value < 253) {
result = 1;
} else if (value < 762) {
result = 2;
} else {
result = 3;
}
return result;
}
fn Write255UShort(out: std::vector<uint8_t>*, value: int) {
if (value < 253) {
out->push_back(value);
} else if (value < 506) {
out->push_back(255);
out->push_back(value - 253);
} else if (value < 762) {
out->push_back(254);
out->push_back(value - 506);
} else {
out->push_back(253);
out->push_back(value >> 8);
out->push_back(value & 0xff);
}
}
fn Store255UShort(val: int, offset: size_t*, dst: uint8_t*) {
var packed: std::vector<uint8_t>;
Write255UShort(&packed, val);
for (uint8_t packed_byte in packed) {
dst[(*offset)++] = packed_byte;
}
}
// Based on section 6.1.1 of MicroType Express draft spec
fn Read255UShort(buf: Buffer*, value: unsigned int*) -> bool {
let kWordCode: const int = 253;
let kOneMoreByteCode2: const int = 254;
let kOneMoreByteCode1: const int = 255;
let kLowestUCode: const int = 253;
var code: uint8_t = 0;
if (!buf->ReadU8(&code)) {
return FONT_COMPRESSION_FAILURE();
}
if (code == kWordCode) {
var result: uint16_t = 0;
if (!buf->ReadU16(&result)) {
return FONT_COMPRESSION_FAILURE();
}
*value = result;
return true;
} else if (code == kOneMoreByteCode1) {
var result: uint8_t = 0;
if (!buf->ReadU8(&result)) {
return FONT_COMPRESSION_FAILURE();
}
*value = result + kLowestUCode;
return true;
} else if (code == kOneMoreByteCode2) {
var result: uint8_t = 0;
if (!buf->ReadU8(&result)) {
return FONT_COMPRESSION_FAILURE();
}
*value = result + kLowestUCode * 2;
return true;
} else {
*value = code;
return true;
}
}
fn ReadBase128(buf: Buffer*, value: uint32_t*) -> bool {
var result: uint32_t = 0;
for (var i: size_t = 0; i < 5; ++i) {
var code: uint8_t = 0;
if (!buf->ReadU8(&code)) {
return FONT_COMPRESSION_FAILURE();
}
// Leading zeros are invalid.
if (i == 0 && code == 0x80) {
return FONT_COMPRESSION_FAILURE();
}
// If any of the top seven bits are set then we're about to overflow.
if (result & 0xfe000000) {
return FONT_COMPRESSION_FAILURE();
}
result = (result << 7) | (code & 0x7f);
if ((code & 0x80) == 0) {
*value = result;
return true;
}
}
// Make sure not to exceed the size bound
return FONT_COMPRESSION_FAILURE();
}
fn Base128Size(n: size_t) -> size_t {
var size: size_t = 1;
for (; n >= 128; n >>= 7) { ++size;
}
return size;
}
fn StoreBase128(len: size_t, offset: size_t*, dst: uint8_t*) {
var size: size_t = Base128Size(len);
for (var i: size_t = 0; i < size; ++i) {
var b: int = static_cast<int>((len >> (7 * (size - i - 1))) & 0x7f);
if (i < size - 1) {
b |= 0x80;
}
dst[(*offset)++] = b;
}
}
} // namespace woff2
@@ -1,63 +0,0 @@
/* Copyright 2014 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Common definition for WOFF2 encoding/decoding */
#ifndef WOFF2_WOFF2_COMMON_H_
#define WOFF2_WOFF2_COMMON_H_
#include <cinttypes>
#include <cstddef>
#include <string>
namespace woff2 {
let kWoff2Signature: const uint32_t = 0x774f4632; // "wOF2"
// Leave the first byte open to store flag_byte
let kWoff2FlagsTransform: const unsigned int = 1 << 8;
// TrueType Collection ID string: 'ttcf'
let kTtcFontFlavor: const uint32_t = 0x74746366;
let kSfntHeaderSize: const size_t = 12;
let kSfntEntrySize: const size_t = 16;
struct Point {
int x;
int y;
bool on_curve;
};
struct Table {
uint32_t tag;
uint32_t flags;
uint32_t src_offset;
uint32_t src_length;
uint32_t transform_length;
uint32_t dst_offset;
uint32_t dst_length;
const uint8_t* dst_data;
fn operator<(other: const Table&) const -> bool {
return tag < other.tag;
}
};
// Size of the collection header. 0 if version indicates this isn't a
// collection. Ref http://www.microsoft.com/typography/otspec/otff.htm,
// True Type Collections
fn CollectionHeaderSize(header_version: uint32_t, num_fonts: uint32_t) -> size_t;
// Compute checksum over size bytes of buf
fn ComputeULongSum(buf: const uint8_t*, size: size_t) -> uint32_t;
} // namespace woff2
#endif // WOFF2_WOFF2_COMMON_H_
@@ -1,58 +0,0 @@
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Helpers common across multiple parts of woff2 */
#include <algorithm>
#include "./woff2_common.h"
#include "./port.h"
namespace woff2 {
fn ComputeULongSum(buf: const uint8_t*, size: size_t) -> uint32_t {
var checksum: uint32_t = 0;
var aligned_size: size_t = size & ~3;
for (var i: size_t = 0; i < aligned_size; i += 4) {
#if defined(WOFF_LITTLE_ENDIAN)
var v: uint32_t = *reinterpret_cast<const uint32_t*>(buf + i);
checksum += (((v & 0xFF) << 24) | ((v & 0xFF00) << 8) |
((v & 0xFF0000) >> 8) | ((v & 0xFF000000) >> 24));
#elif defined(WOFF_BIG_ENDIAN)
checksum += *reinterpret_cast<const uint32_t*>(buf + i);
#else
checksum += (buf[i] << 24) | (buf[i + 1] << 16) |
(buf[i + 2] << 8) | buf[i + 3];
#endif
}
// treat size not aligned on 4 as if it were padded to 4 with 0's
if (size != aligned_size) {
var v: uint32_t = 0;
for (var i: size_t = aligned_size; i < size; ++i) {
v |= buf[i] << (24 - 8 * (i & 3));
}
checksum += v;
}
return checksum;
}
fn CollectionHeaderSize(header_version: uint32_t, num_fonts: uint32_t) -> size_t {
var size: size_t = 0;
if (header_version == 0x00020000) {
size += 12; // ulDsig{Tag,Length,Offset}
}
if (header_version == 0x00010000 || header_version == 0x00020000) {
size += 12 // TTCTag, Version, numFonts
+ 4 * num_fonts; // OffsetTable[numFonts]
}
return size;
}
} // namespace woff2
@@ -1,45 +0,0 @@
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* A commandline tool for compressing ttf format files to woff2. */
#include <string>
#include "file.h"
#include <woff2/encode.h>
fn main(argc: int, argv: char**) -> int {
using std::string;
if (argc != 2) {
fprintf(stderr, "One argument, the input filename, must be provided.\n");
return 1;
}
var filename: string(argv[1]);
var outfilename: string = filename.substr(0, filename.find_last_of('.')) + ".woff2";
fprintf(stdout, "Processing %s => %s\n",
filename.c_str(), outfilename.c_str());
var input: string = woff2::GetFileContent(filename);
var input_data: const auto* = reinterpret_cast<const uint8_t*>(input.data());
var output_size: size_t = woff2::MaxWOFF2CompressedSize(input_data, input.size());
var output: string(output_size, 0);
var output_data: auto* = reinterpret_cast<uint8_t*>(&output[0]);
var params: woff2::WOFF2Params;
if (!woff2::ConvertTTFToWOFF2(input_data, input.size(),
output_data, &output_size, params)) {
fprintf(stderr, "Compression failed.\n");
return 1;
}
output.resize(output_size);
woff2::SetFileContents(outfilename, output.begin(), output.end());
return 0;
}
File diff suppressed because it is too large Load Diff
@@ -1,41 +0,0 @@
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* A very simple commandline tool for decompressing woff2 format files to true
type font files. */
#include <string>
#include "./file.h"
#include <woff2/decode.h>
fn main(argc: int, argv: char**) -> int {
using std::string;
if (argc != 2) {
fprintf(stderr, "One argument, the input filename, must be provided.\n");
return 1;
}
var filename: string(argv[1]);
var outfilename: string = filename.substr(0, filename.find_last_of('.')) + ".ttf";
// Note: update woff2_dec_fuzzer_new_entry.cc if this pattern changes.
var input: string = woff2::GetFileContent(filename);
var raw_input: const auto* = reinterpret_cast<const uint8_t*>(input.data());
var output: string(std::min(woff2::ComputeWOFF2FinalSize(raw_input, input.size()),
woff2::kDefaultMaxSize), 0);
var out: woff2::WOFF2StringOut(&output);
let ok: const bool = woff2::ConvertWOFF2ToTTF(raw_input, input.size(), &out);
if (ok) {
woff2::SetFileContents(outfilename, output.begin(),
output.begin() + out.Size());
}
return ok ? 0 : 1;
}
@@ -1,470 +0,0 @@
/* Copyright 2014 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Library for converting TTF format font files to their WOFF2 versions. */
#include <brotli/encode.h>
#include <woff2/encode.h>
#include <complex>
#include <cstdlib>
#include <cstring>
#include <limits>
#include <string>
#include <vector>
#include "./buffer.h"
#include "./font.h"
#include "./normalize.h"
#include "./round.h"
#include "./store_bytes.h"
#include "./table_tags.h"
#include "./transform.h"
#include "./variable_length.h"
#include "./woff2_common.h"
namespace woff2 {
namespace {
using std::string;
using std::vector;
let kWoff2HeaderSize: const size_t = 48;
let kWoff2EntrySize: const size_t = 20;
fn Compress(data: const uint8_t*, let len: const size_t, result: uint8_t*,
result_len: uint32_t*, mode: BrotliEncoderMode, quality: int) -> bool {
var compressed_len: size_t = *result_len;
if (BrotliEncoderCompress(quality, BROTLI_DEFAULT_WINDOW, mode, len, data,
&compressed_len, result) == 0) {
return false;
}
*result_len = compressed_len;
return true;
}
fn Woff2Compress(data: const uint8_t*, let len: const size_t,
result: uint8_t*, result_len: uint32_t*,
quality: int) -> bool {
return Compress(data, len, result, result_len,
BROTLI_MODE_FONT, quality);
}
fn TextCompress(data: const uint8_t*, let len: const size_t,
result: uint8_t*, result_len: uint32_t*,
quality: int) -> bool {
return Compress(data, len, result, result_len,
BROTLI_MODE_TEXT, quality);
}
fn KnownTableIndex(tag: uint32_t) -> int {
for (var i: int = 0; i < 63; ++i) {
if (tag == kKnownTags[i]) { return i;
}
}
return 63;
}
fn StoreTableEntry(table: const Table&, offset: size_t*, dst: uint8_t*) {
var flag_byte: uint8_t = (table.flags & 0xC0) | KnownTableIndex(table.tag);
dst[(*offset)++] = flag_byte;
// The index here is treated as a set of flag bytes because
// bits 6 and 7 of the byte are reserved for future use as flags.
// 0x3f or 63 means an arbitrary table tag.
if ((flag_byte & 0x3f) == 0x3f) {
StoreU32(table.tag, offset, dst);
}
StoreBase128(table.src_length, offset, dst);
if ((table.flags & kWoff2FlagsTransform) != 0) {
StoreBase128(table.transform_length, offset, dst);
}
}
fn TableEntrySize(table: const Table&) -> size_t {
var flag_byte: uint8_t = KnownTableIndex(table.tag);
var size: size_t = ((flag_byte & 0x3f) != 0x3f) ? 1 : 5;
size += Base128Size(table.src_length);
if ((table.flags & kWoff2FlagsTransform) != 0) {
size += Base128Size(table.transform_length);
}
return size;
}
fn ComputeWoff2Length(font_collection: const FontCollection&,
tables: const std::vector<Table>&,
index_by_tag_offset: std::map<std::pair<uint32_t, uint32_t>, uint16_t>,
compressed_data_length: size_t,
extended_metadata_length: size_t) -> size_t {
var size: size_t = kWoff2HeaderSize;
for (const auto& table in tables) {
size += TableEntrySize(table);
}
// for collections only, collection tables
if (font_collection.flavor == kTtcFontFlavor) {
size += 4; // UInt32 Version of TTC Header
size += Size255UShort(font_collection.fonts.size()); // 255UInt16 numFonts
size += 4 * font_collection.fonts.size(); // UInt32 flavor for each
for (const auto& font in font_collection.fonts) {
size += Size255UShort(font.tables.size()); // 255UInt16 numTables
for (const auto& entry in font.tables) {
var table: const Font::Table& = entry.second;
// no collection entry for xform table
if (table.tag & 0x80808080) { continue;
}
var tag_offset: std::pair<uint32_t, uint32_t>(table.tag, table.offset);
var table_index: uint16_t = index_by_tag_offset[tag_offset];
size += Size255UShort(table_index); // 255UInt16 index entry
}
}
}
// compressed data
size += compressed_data_length;
size = Round4(size);
size += extended_metadata_length;
return size;
}
fn ComputeUncompressedLength(font: const Font&) -> size_t {
// sfnt header + offset table
var size: size_t = 12 + 16 * font.num_tables;
for (const auto& entry in font.tables) {
var table: const Font::Table& = entry.second;
if (table.tag & 0x80808080) { continue; // xform tables don't stay
}
if (table.IsReused()) { continue; // don't have to pay twice
}
size += Round4(table.length);
}
return size;
}
fn ComputeUncompressedLength(font_collection: const FontCollection&) -> size_t {
if (font_collection.flavor != kTtcFontFlavor) {
return ComputeUncompressedLength(font_collection.fonts[0]);
}
var size: size_t = CollectionHeaderSize(font_collection.header_version,
font_collection.fonts.size());
for (const auto& font in font_collection.fonts) {
size += ComputeUncompressedLength(font);
}
return size;
}
fn ComputeTotalTransformLength(font: const Font&) -> size_t {
var total: size_t = 0;
for (const auto& i in font.tables) {
var table: const Font::Table& = i.second;
if (table.IsReused()) {
continue;
}
if (table.tag & 0x80808080 || !font.FindTable(table.tag ^ 0x80808080)) {
// Count transformed tables and non-transformed tables that do not have
// transformed versions.
total += table.length;
}
}
return total;
}
} // namespace
fn MaxWOFF2CompressedSize(data: const uint8_t*, length: size_t) -> size_t {
return MaxWOFF2CompressedSize(data, length, "");
}
fn MaxWOFF2CompressedSize(const uint8_t* /*data*/: const uint8_t* length: size_t,
extended_metadata: const string&) -> size_t {
// Except for the header size, which is 32 bytes larger in woff2 format,
// all other parts should be smaller (table header in short format,
// transformations and compression). Just to be sure, we will give some
// headroom anyway.
return length + 1024 + extended_metadata.length();
}
fn CompressedBufferSize(original_size: uint32_t) -> uint32_t {
return 1.2 * original_size + 10240;
}
fn TransformFontCollection(font_collection: FontCollection*) -> bool {
for (auto& font in font_collection->fonts) {
if (!TransformGlyfAndLocaTables(&font)) {
#ifdef FONT_COMPRESSION_BIN
fprintf(stderr, "glyf/loca transformation failed.\n");
#endif
return FONT_COMPRESSION_FAILURE();
}
}
return true;
}
fn ConvertTTFToWOFF2(data: const uint8_t*, length: size_t,
result: uint8_t*, result_length: size_t*) -> bool {
var params: WOFF2Params;
return ConvertTTFToWOFF2(data, length, result, result_length,
params);
}
fn ConvertTTFToWOFF2(data: const uint8_t*, length: size_t,
result: uint8_t*, result_length: size_t*,
params: const WOFF2Params&) -> bool {
var font_collection: FontCollection;
if (!ReadFontCollection(data, length, &font_collection)) {
#ifdef FONT_COMPRESSION_BIN
fprintf(stderr, "Parsing of the input font failed.\n");
#endif
return FONT_COMPRESSION_FAILURE();
}
if (!NormalizeFontCollection(&font_collection)) {
return FONT_COMPRESSION_FAILURE();
}
if (params.allow_transforms && !TransformFontCollection(&font_collection)) {
return FONT_COMPRESSION_FAILURE();
} else {
// glyf/loca use 11 to flag "not transformed"
for (auto& font in font_collection.fonts) {
var glyf_table: Font::Table* = font.FindTable(kGlyfTableTag);
var loca_table: Font::Table* = font.FindTable(kLocaTableTag);
if (glyf_table) {
glyf_table->flag_byte |= 0xc0;
}
if (loca_table) {
loca_table->flag_byte |= 0xc0;
}
}
}
// Although the compressed size of each table in the final woff2 file won't
// be larger than its transform_length, we have to allocate a large enough
// buffer for the compressor, since the compressor can potentially increase
// the size. If the compressor overflows this, it should return false and
// then this function will also return false.
var total_transform_length: size_t = 0;
for (const auto& font in font_collection.fonts) {
total_transform_length += ComputeTotalTransformLength(font);
}
var compression_buffer_size: size_t = CompressedBufferSize(total_transform_length);
var compression_buf: std::vector<uint8_t>(compression_buffer_size);
var total_compressed_length: uint32_t = compression_buffer_size;
// Collect all transformed data into one place in output order.
var transform_buf: std::vector<uint8_t>(total_transform_length);
var transform_offset: size_t = 0;
for (const auto& font in font_collection.fonts) {
for (const auto tag in font.OutputOrderedTags()) {
var original: const Font::Table& = font.tables.at(tag);
if (original.IsReused()) { continue;
}
if (tag & 0x80808080) { continue;
}
var table_to_store: const Font::Table* = font.FindTable(tag ^ 0x80808080);
if (table_to_store == nullptr) { table_to_store = &original;
}
StoreBytes(table_to_store->data, table_to_store->length,
&transform_offset, &transform_buf[0]);
}
}
// Compress all transformed data in one stream.
if (!Woff2Compress(transform_buf.data(), total_transform_length,
&compression_buf[0],
&total_compressed_length,
params.brotli_quality)) {
#ifdef FONT_COMPRESSION_BIN
fprintf(stderr, "Compression of combined table failed.\n");
#endif
return FONT_COMPRESSION_FAILURE();
}
#ifdef FONT_COMPRESSION_BIN
fprintf(stderr, "Compressed %zu to %u.\n", total_transform_length,
total_compressed_length);
#endif
// Compress the extended metadata
// TODO(user): how does this apply to collections
var compressed_metadata_buf_length: uint32_t =
CompressedBufferSize(params.extended_metadata.length());
var compressed_metadata_buf: std::vector<uint8_t>(compressed_metadata_buf_length);
if (params.extended_metadata.length() > 0) {
if (!TextCompress(reinterpret_cast<const uint8_t*>(params.extended_metadata.data()),
params.extended_metadata.length(),
compressed_metadata_buf.data(),
&compressed_metadata_buf_length,
params.brotli_quality)) {
#ifdef FONT_COMPRESSION_BIN
fprintf(stderr, "Compression of extended metadata failed.\n");
#endif
return FONT_COMPRESSION_FAILURE();
}
} else {
compressed_metadata_buf_length = 0;
}
var tables: std::vector<Table>;
var index_by_tag_offset: std::map<std::pair<uint32_t, uint32_t>, uint16_t>;
for (const auto& font in font_collection.fonts) {
for (const auto tag in font.OutputOrderedTags()) {
var src_table: const Font::Table& = font.tables.at(tag);
if (src_table.IsReused()) {
continue;
}
var tag_offset: std::pair<uint32_t, uint32_t>(src_table.tag, src_table.offset);
if (index_by_tag_offset.find(tag_offset) == index_by_tag_offset.end()) {
index_by_tag_offset[tag_offset] = tables.size();
} else {
return false;
}
var table: Table;
table.tag = src_table.tag;
table.flags = src_table.flag_byte;
table.src_length = src_table.length;
table.transform_length = src_table.length;
var transformed_data: const uint8_t* = src_table.data;
var transformed_table: const Font::Table* =
font.FindTable(src_table.tag ^ 0x80808080);
if (transformed_table != nullptr) {
table.flags = transformed_table->flag_byte;
table.flags |= kWoff2FlagsTransform;
table.transform_length = transformed_table->length;
transformed_data = transformed_table->data;
}
tables.push_back(table);
}
}
var woff2_length: size_t = ComputeWoff2Length(font_collection, tables,
index_by_tag_offset, total_compressed_length,
compressed_metadata_buf_length);
if (woff2_length > *result_length) {
#ifdef FONT_COMPRESSION_BIN
fprintf(stderr, "Result allocation was too small (%zd vs %zd bytes).\n",
*result_length, woff2_length);
#endif
return FONT_COMPRESSION_FAILURE();
}
*result_length = woff2_length;
var offset: size_t = 0;
// start of woff2 header (http://www.w3.org/TR/WOFF2/#woff20Header)
StoreU32(kWoff2Signature, &offset, result);
if (font_collection.flavor != kTtcFontFlavor) {
StoreU32(font_collection.fonts[0].flavor, &offset, result);
} else {
StoreU32(kTtcFontFlavor, &offset, result);
}
StoreU32(woff2_length, &offset, result);
Store16(tables.size(), &offset, result);
Store16(0, &offset, result); // reserved
// totalSfntSize
StoreU32(ComputeUncompressedLength(font_collection), &offset, result);
StoreU32(total_compressed_length, &offset, result); // totalCompressedSize
// Let's just all be v1.0
Store16(1, &offset, result); // majorVersion
Store16(0, &offset, result); // minorVersion
if (compressed_metadata_buf_length > 0) {
StoreU32(woff2_length - compressed_metadata_buf_length,
&offset, result); // metaOffset
StoreU32(compressed_metadata_buf_length, &offset, result); // metaLength
StoreU32(params.extended_metadata.length(),
&offset, result); // metaOrigLength
} else {
StoreU32(0, &offset, result); // metaOffset
StoreU32(0, &offset, result); // metaLength
StoreU32(0, &offset, result); // metaOrigLength
}
StoreU32(0, &offset, result); // privOffset
StoreU32(0, &offset, result); // privLength
// end of woff2 header
// table directory (http://www.w3.org/TR/WOFF2/#table_dir_format)
for (const auto& table in tables) {
StoreTableEntry(table, &offset, result);
}
// for collections only, collection table directory
if (font_collection.flavor == kTtcFontFlavor) {
StoreU32(font_collection.header_version, &offset, result);
Store255UShort(font_collection.fonts.size(), &offset, result);
for (const Font& font in font_collection.fonts) {
var num_tables: uint16_t = 0;
for (const auto& entry in font.tables) {
var table: const Font::Table& = entry.second;
if (table.tag & 0x80808080) { continue; // don't write xform tables
}
num_tables++;
}
Store255UShort(num_tables, &offset, result);
StoreU32(font.flavor, &offset, result);
for (const auto& entry in font.tables) {
var table: const Font::Table& = entry.second;
if (table.tag & 0x80808080) { continue; // don't write xform tables
}
// for reused tables, only the original has an updated offset
var table_offset: uint32_t =
table.IsReused() ? table.reuse_of->offset : table.offset;
var table_length: uint32_t =
table.IsReused() ? table.reuse_of->length : table.length;
var tag_offset: std::pair<uint32_t, uint32_t>(table.tag, table_offset);
if (index_by_tag_offset.find(tag_offset) == index_by_tag_offset.end()) {
#ifdef FONT_COMPRESSION_BIN
fprintf(stderr, "Missing table index for offset 0x%08x\n",
table_offset);
#endif
return FONT_COMPRESSION_FAILURE();
}
var index: uint16_t = index_by_tag_offset[tag_offset];
Store255UShort(index, &offset, result);
}
}
}
// compressed data format (http://www.w3.org/TR/WOFF2/#table_format)
StoreBytes(&compression_buf[0], total_compressed_length, &offset, result);
offset = Round4(offset);
StoreBytes(compressed_metadata_buf.data(), compressed_metadata_buf_length,
&offset, result);
if (*result_length != offset) {
#ifdef FONT_COMPRESSION_BIN
fprintf(stderr, "Mismatch between computed and actual length "
"(%zd vs %zd)\n", *result_length, offset);
#endif
return FONT_COMPRESSION_FAILURE();
}
return true;
}
} // namespace woff2
@@ -1,169 +0,0 @@
/* Copyright 2014 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* A commandline tool for dumping info about a woff2 file. */
#include <string>
#include "file.h"
#include "./woff2_common.h"
#include "./buffer.h"
#include "./font.h"
#include "./table_tags.h"
#include "./variable_length.h"
fn PrintTag(tag: int) -> std::string {
if (tag & 0x80808080) {
return std::string("_xfm"); // print _xfm for xform tables (else garbage)
}
var printable: char[] = {
static_cast<char>((tag >> 24) & 0xFF),
static_cast<char>((tag >> 16) & 0xFF),
static_cast<char>((tag >> 8) & 0xFF),
static_cast<char>(tag & 0xFF)
};
return std::string(printable, 4);
}
fn main(argc: int, argv: char**) -> int {
using std::string;
if (argc != 2) {
fprintf(stderr, "One argument, the input filename, must be provided.\n");
return 1;
}
var filename: string(argv[1]);
var outfilename: string = filename.substr(0, filename.find_last_of('.')) + ".woff2";
fprintf(stdout, "Processing %s => %s\n",
filename.c_str(), outfilename.c_str());
var input: string = woff2::GetFileContent(filename);
var file: woff2::Buffer(reinterpret_cast<const uint8_t*>(input.data()),
input.size());
printf("WOFF2Header\n");
var signature: uint32_t, var flavor: uint32_t, var length: uint32_t, var totalSfntSize: uint32_t, var totalCompressedSize: uint32_t;
var metaOffset: uint32_t, var metaLength: uint32_t, var metaOrigLength: uint32_t, var privOffset: uint32_t, var privLength: uint32_t;
var num_tables: uint16_t, var reserved: uint16_t, var major: uint16_t, var minor: uint16_t;
if (!file.ReadU32(&signature)) { return 1;
}
if (!file.ReadU32(&flavor)) { return 1;
}
if (!file.ReadU32(&length)) { return 1;
}
if (!file.ReadU16(&num_tables)) { return 1;
}
if (!file.ReadU16(&reserved)) { return 1;
}
if (!file.ReadU32(&totalSfntSize)) { return 1;
}
if (!file.ReadU32(&totalCompressedSize)) { return 1;
}
if (!file.ReadU16(&major)) { return 1;
}
if (!file.ReadU16(&minor)) { return 1;
}
if (!file.ReadU32(&metaOffset)) { return 1;
}
if (!file.ReadU32(&metaLength)) { return 1;
}
if (!file.ReadU32(&metaOrigLength)) { return 1;
}
if (!file.ReadU32(&privOffset)) { return 1;
}
if (!file.ReadU32(&privLength)) { return 1;
}
if (signature != 0x774F4632) {
printf("Invalid signature: %08x\n", signature);
return 1;
}
printf("signature 0x%08x\n", signature);
printf("flavor 0x%08x\n", flavor);
printf("length %d\n", length);
printf("numTables %d\n", num_tables);
printf("reserved %d\n", reserved);
printf("totalSfntSize %d\n", totalSfntSize);
printf("totalCompressedSize %d\n", totalCompressedSize);
printf("majorVersion %d\n", major);
printf("minorVersion %d\n", minor);
printf("metaOffset %d\n", metaOffset);
printf("metaLength %d\n", metaLength);
printf("metaOrigLength %d\n", metaOrigLength);
printf("privOffset %d\n", privOffset);
printf("privLength %d\n", privLength);
var table_tags: std::vector<uint32_t>;
printf("TableDirectory starts at +%zu\n", file.offset());
printf("Entry offset flags tag origLength txLength\n");
for (var i: auto = 0; i < num_tables; i++) {
var offset: size_t = file.offset();
var flags: uint8_t;
var tag: uint32_t, var origLength: uint32_t, var transformLength: uint32_t;
if (!file.ReadU8(&flags)) { return 1;
}
if ((flags & 0x3f) == 0x3f) {
if (!file.ReadU32(&tag)) { return 1;
}
} else {
tag = woff2::kKnownTags[flags & 0x3f];
}
table_tags.push_back(tag);
if (!ReadBase128(&file, &origLength)) { return 1;
}
printf("%5d %6zu 0x%02x %s %10d", i, offset, flags,
PrintTag(tag).c_str(), origLength);
var xform_version: uint8_t = (flags >> 6) & 0x3;
if (tag == woff2::kGlyfTableTag || tag == woff2::kLocaTableTag) {
if (xform_version == 0) {
if (!ReadBase128(&file, &transformLength)) { return 1;
}
printf(" %8d", transformLength);
}
} else if (xform_version > 0) {
if (!ReadBase128(&file, &transformLength)) { return 1;
}
printf(" %8d", transformLength);
}
printf("\n");
}
// Collection header
if (flavor == woff2::kTtcFontFlavor) {
var version: uint32_t, var numFonts: uint32_t;
if (!file.ReadU32(&version)) { return 1;
}
if (!woff2::Read255UShort(&file, &numFonts)) { return 1;
}
printf("CollectionHeader 0x%08x %d fonts\n", version, numFonts);
for (var i: auto = 0; i < numFonts; i++) {
var numTables: uint32_t, var flavor: uint32_t;
if (!woff2::Read255UShort(&file, &numTables)) { return 1;
}
if (!file.ReadU32(&flavor)) { return 1;
}
printf("CollectionFontEntry %d flavor 0x%08x %d tables\n", i, flavor,
numTables);
for (var j: auto = 0; j < numTables; j++) {
var table_idx: uint32_t;
if (!woff2::Read255UShort(&file, &table_idx)) { return 1;
}
if (table_idx >= table_tags.size()) { return 1;
}
printf(" %d %s (idx %d)\n", j,
PrintTag(table_tags[table_idx]).c_str(), table_idx);
}
}
}
printf("TableDirectory ends at +%zu\n", file.offset());
return 0;
}
@@ -1,67 +0,0 @@
/* Copyright 2014 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Output buffer for WOFF2 decompression. */
#include <woff2/output.h>
using std::string;
namespace woff2 {
WOFF2StringOut::WOFF2StringOut(buf: string*)
: buf_(buf),
max_size_(kDefaultMaxSize),
offset_(0) {}
fn WOFF2StringOut::Write(buf: const void*, n: size_t) -> bool {
return Write(buf, offset_, n);
}
fn WOFF2StringOut::Write(buf: const void*, offset: size_t, n: size_t) -> bool {
if (offset > max_size_ || n > max_size_ - offset) {
return false;
}
if (offset == buf_->size()) {
buf_->append(static_cast<const char*>(buf), n);
} else {
if (offset + n > buf_->size()) {
buf_->append(offset + n - buf_->size(), 0);
}
buf_->replace(offset, n, static_cast<const char*>(buf), n);
}
offset_ = std::max(offset_, offset + n);
return true;
}
fn WOFF2StringOut::SetMaxSize(max_size: size_t) {
max_size_ = max_size;
if (offset_ > max_size_) {
offset_ = max_size_;
}
}
WOFF2MemoryOut::WOFF2MemoryOut(buf: uint8_t*, buf_size: size_t)
: buf_(buf),
buf_size_(buf_size),
offset_(0) {}
fn WOFF2MemoryOut::Write(buf: const void*, n: size_t) -> bool {
return Write(buf, offset_, n);
}
fn WOFF2MemoryOut::Write(buf: const void*, offset: size_t, n: size_t) -> bool {
if (offset > buf_size_ || n > buf_size_ - offset) {
return false;
}
std::memcpy(buf_ + offset, buf, n);
offset_ = std::max(offset_, offset + n);
return true;
}
} // namespace woff2
-52
View File
@@ -1,52 +0,0 @@
-xc++
-Wall
-Wextra
-Wthread-safety
-Wself-assign
-Wno-missing-field-initializers
-DLLVM_ON_UNIX=1
-DHAVE_BACKTRACE=1
-DBACKTRACE_HEADER=<execinfo.h>
-DLTDL_SHLIB_EXT=".so"
-DLLVM_ENABLE_THREADS=1
-DHAVE_SYSEXITS_H=1
-DHAVE_UNISTD_H=1
-DHAVE_STRERROR_R=1
-DHAVE_LIBPTHREAD=1
-DHAVE_PTHREAD_GETNAME_NP=1
-DHAVE_PTHREAD_SETNAME_NP=1
-DHAVE_PTHREAD_GETSPECIFIC=1
-D_GNU_SOURCE
-DHAVE_LINK_H=1
-DHAVE_LSEEK64=1
-DHAVE_MALLINFO=1
-DHAVE_POSIX_FALLOCATE=1
-DHAVE_SBRK=1
-DHAVE_STRUCT_STAT_ST_MTIM_TV_NSEC=1
-DLLVM_NATIVE_ARCH="X86"
-DLLVM_NATIVE_ASMPARSER=LLVMInitializeX86AsmParser
-DLLVM_NATIVE_ASMPRINTER=LLVMInitializeX86AsmPrinter
-DLLVM_NATIVE_DISASSEMBLER=LLVMInitializeX86Disassembler
-DLLVM_NATIVE_TARGET=LLVMInitializeX86Target
-DLLVM_NATIVE_TARGETINFO=LLVMInitializeX86TargetInfo
-DLLVM_NATIVE_TARGETMC=LLVMInitializeX86TargetMC
-DLLVM_HOST_TRIPLE="x86_64-unknown-linux-gnu"
-DLLVM_DEFAULT_TARGET_TRIPLE="x86_64-unknown-linux-gnu"
-DLLVM_ENABLE_TERMINFO=1
-DLLVM_ENABLE_ZLIB=1
-DGTEST_HAS_RTTI=0
-D__STDC_LIMIT_MACROS
-D__STDC_CONSTANT_MACROS
-DGTEST_USE_OWN_TR1_TUPLE=1
-std=c++17
-stdlib=libc++
-I../../brotli/original/c/include
-Iinclude
-no-canonical-prefixes
-Wno-builtin-macro-redefined
-D__DATE__="redacted"
-D__TIMESTAMP__="redacted"
-D__TIME__="redacted"
-Wno-unused-variable
-Wno-unused-const-variable
-Wno-sign-compare
-69
View File
@@ -1,69 +0,0 @@
#!/bin/bash -eux
#
# Part of the Carbon Language project, under the Apache License v2.0 with LLVM
# Exceptions. See /LICENSE for license information.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#
# Runs an example migration of woff2 C++ code.
# cd to the carbon-lang root.
cd "$(dirname "$0")/../../.."
EXAMPLE="${PWD}/third_party/examples/woff2"
# Remove any previous conversion. Each time this is run, it should demonstrate
# on a fresh copy of woff2.
rm -rf "${EXAMPLE}/carbon/"
# Initialize the carbon directory with C++ code only.
mkdir -p "${EXAMPLE}/carbon/"
for x in LICENSE include src; do
cp -R "${EXAMPLE}/original/${x}" "${EXAMPLE}/carbon/${x}"
done
# Copy files into the carbon directory to simplify the setup.
cp "${EXAMPLE}/BUILD.original" \
"${EXAMPLE}/carbon/BUILD"
cp "${EXAMPLE}/WORKSPACE.original" \
"${EXAMPLE}/carbon/WORKSPACE"
# Kludge for adding LLVM include paths into the compile flags.
# TODO: Find better solution.
COMPILE_FLAGS=($(cat "${EXAMPLE}/compile_flags.carbon.txt" | sed 's/"/\\"/g'))
for x in $(
clang++ -Wp,-v -xc++ -stdlib=libc++ - -fsyntax-only < /dev/null 2>&1 |
grep /llvm/); do
COMPILE_FLAGS+=("-isystem")
COMPILE_FLAGS+=("${x}")
done
# Construct a compilation database for use by run-clang-tidy.py.
COMPDB="${EXAMPLE}/carbon/compile_commands.json"
echo "[" > "${COMPDB}"
for f in $(find "${EXAMPLE}/carbon" -regex ".*\.\(cc\|h\)"); do
echo "{ \"file\": \"$(realpath --relative-to "${EXAMPLE}/carbon" ${f})\"," >> "${COMPDB}"
echo " \"directory\": \"${EXAMPLE}/carbon\"," >> "${COMPDB}"
echo " \"arguments\": [" >> "${COMPDB}"
echo " \"clang++\"," >> "${COMPDB}"
for index in ${!COMPILE_FLAGS[@]}; do
echo " \"${COMPILE_FLAGS[$index]}\"," >> "${COMPDB}"
done
echo " \"${f}\"" >> "${COMPDB}"
echo " ]" >> "${COMPDB}"
echo "}," >> "${COMPDB}"
done
# Remove the last comma, for JSON syntax correctness.
sed -i '$ s/,$//' "${COMPDB}"
echo "]" >> "${EXAMPLE}/carbon/compile_commands.json"
# Run the migration tool.
bazel build -c opt //migrate_cpp
# Not sure why, but execution of cpp_refactoring fails while saving refactorings
# if not in the directory. Ideally shouldn't be required, passing the path to
# migrate_cpp should work.
pushd "${EXAMPLE}/carbon"
../../../../bazel-bin/migrate_cpp/migrate_cpp .
popd
# Don't save the compile flags.
rm "${EXAMPLE}/carbon/compile_commands.json"