2020-05-22 04:47:44 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
|
|
#ifndef GFX_OTS_UTILS_H
|
|
|
|
#define GFX_OTS_UTILS_H
|
|
|
|
|
|
|
|
#include "gfxFontUtils.h"
|
|
|
|
|
|
|
|
#include "opentype-sanitiser.h"
|
|
|
|
|
|
|
|
struct gfxOTSMozAlloc {
|
|
|
|
void* Grow(void* aPtr, size_t aLength) { return moz_xrealloc(aPtr, aLength); }
|
|
|
|
void* ShrinkToFit(void* aPtr, size_t aLength) {
|
|
|
|
return moz_xrealloc(aPtr, aLength);
|
|
|
|
}
|
|
|
|
void Free(void* aPtr) { free(aPtr); }
|
|
|
|
};
|
|
|
|
|
|
|
|
// Based on ots::ExpandingMemoryStream from ots-memory-stream.h,
|
|
|
|
// adapted to use Mozilla allocators and to allow the final
|
|
|
|
// memory buffer to be adopted by the client.
|
|
|
|
template <typename AllocT = gfxOTSMozAlloc>
|
|
|
|
class gfxOTSExpandingMemoryStream : public ots::OTSStream {
|
|
|
|
public:
|
|
|
|
// limit output/expansion to 256MB by default
|
|
|
|
enum { DEFAULT_LIMIT = 256 * 1024 * 1024 };
|
|
|
|
|
2020-05-22 15:48:55 +00:00
|
|
|
explicit gfxOTSExpandingMemoryStream(size_t initial,
|
|
|
|
size_t limit = DEFAULT_LIMIT)
|
2020-05-22 04:47:44 +00:00
|
|
|
: mLength(initial), mLimit(limit), mOff(0) {
|
|
|
|
mPtr = mAlloc.Grow(nullptr, mLength);
|
|
|
|
}
|
|
|
|
|
|
|
|
~gfxOTSExpandingMemoryStream() { mAlloc.Free(mPtr); }
|
|
|
|
|
2022-09-10 16:10:38 +00:00
|
|
|
size_t size() override { return mLimit; }
|
|
|
|
|
2020-05-22 04:47:44 +00:00
|
|
|
// Return the buffer, resized to fit its contents (as it may have been
|
|
|
|
// over-allocated during growth), and give up ownership of it so the
|
|
|
|
// caller becomes responsible to call free() when finished with it.
|
|
|
|
auto forget() {
|
|
|
|
auto p = mAlloc.ShrinkToFit(mPtr, mOff);
|
|
|
|
mPtr = nullptr;
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool WriteRaw(const void* data, size_t length) override {
|
|
|
|
if ((mOff + length > mLength) ||
|
|
|
|
(mLength > std::numeric_limits<size_t>::max() - mOff)) {
|
|
|
|
if (mLength == mLimit) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
size_t newLength = (mLength + 1) * 2;
|
|
|
|
if (newLength < mLength) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (newLength > mLimit) {
|
|
|
|
newLength = mLimit;
|
|
|
|
}
|
|
|
|
mPtr = mAlloc.Grow(mPtr, newLength);
|
|
|
|
mLength = newLength;
|
|
|
|
return WriteRaw(data, length);
|
|
|
|
}
|
|
|
|
std::memcpy(static_cast<char*>(mPtr) + mOff, data, length);
|
|
|
|
mOff += length;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Seek(off_t position) override {
|
|
|
|
if (position < 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (static_cast<size_t>(position) > mLength) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
mOff = position;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
off_t Tell() const override { return mOff; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
AllocT mAlloc;
|
|
|
|
void* mPtr;
|
|
|
|
size_t mLength;
|
|
|
|
const size_t mLimit;
|
|
|
|
off_t mOff;
|
|
|
|
};
|
|
|
|
|
|
|
|
class MOZ_STACK_CLASS gfxOTSContext : public ots::OTSContext {
|
|
|
|
public:
|
|
|
|
gfxOTSContext() {
|
|
|
|
using namespace mozilla;
|
|
|
|
|
|
|
|
// Whether to apply OTS validation to OpenType Layout tables
|
|
|
|
mCheckOTLTables = StaticPrefs::gfx_downloadable_fonts_otl_validation();
|
|
|
|
// Whether to preserve Variation tables in downloaded fonts
|
|
|
|
mCheckVariationTables =
|
|
|
|
StaticPrefs::gfx_downloadable_fonts_validate_variation_tables();
|
|
|
|
// Whether to preserve color bitmap glyphs
|
|
|
|
mKeepColorBitmaps =
|
|
|
|
StaticPrefs::gfx_downloadable_fonts_keep_color_bitmaps();
|
2022-10-27 20:55:04 +00:00
|
|
|
// Whether to preserve SVG glyphs (which can be expensive in Core Text,
|
|
|
|
// so better to drop them if we're not going to render them anyhow).
|
|
|
|
mKeepSVG = StaticPrefs::gfx_font_rendering_opentype_svg_enabled();
|
2020-05-22 04:47:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual ots::TableAction GetTableAction(uint32_t aTag) override {
|
2022-10-27 20:55:04 +00:00
|
|
|
// Pass through or validate OTL and Variation tables, depending on prefs.
|
2020-05-22 04:47:44 +00:00
|
|
|
if ((!mCheckOTLTables && (aTag == TRUETYPE_TAG('G', 'D', 'E', 'F') ||
|
|
|
|
aTag == TRUETYPE_TAG('G', 'P', 'O', 'S') ||
|
2022-08-04 21:24:11 +00:00
|
|
|
aTag == TRUETYPE_TAG('G', 'S', 'U', 'B')))) {
|
|
|
|
return ots::TABLE_ACTION_PASSTHRU;
|
|
|
|
}
|
|
|
|
auto isVariationTable = [](uint32_t aTag) -> bool {
|
|
|
|
return aTag == TRUETYPE_TAG('a', 'v', 'a', 'r') ||
|
|
|
|
aTag == TRUETYPE_TAG('c', 'v', 'a', 'r') ||
|
|
|
|
aTag == TRUETYPE_TAG('f', 'v', 'a', 'r') ||
|
|
|
|
aTag == TRUETYPE_TAG('g', 'v', 'a', 'r') ||
|
|
|
|
aTag == TRUETYPE_TAG('H', 'V', 'A', 'R') ||
|
|
|
|
aTag == TRUETYPE_TAG('M', 'V', 'A', 'R') ||
|
|
|
|
aTag == TRUETYPE_TAG('S', 'T', 'A', 'T') ||
|
|
|
|
aTag == TRUETYPE_TAG('V', 'V', 'A', 'R');
|
|
|
|
};
|
|
|
|
if (!mCheckVariationTables && isVariationTable(aTag)) {
|
|
|
|
return ots::TABLE_ACTION_PASSTHRU;
|
|
|
|
}
|
|
|
|
if (!gfxPlatform::HasVariationFontSupport() && isVariationTable(aTag)) {
|
|
|
|
return ots::TABLE_ACTION_DROP;
|
|
|
|
}
|
2022-10-27 20:55:04 +00:00
|
|
|
// Preserve SVG table if OpenType-SVG rendering is enabled.
|
|
|
|
if (aTag == TRUETYPE_TAG('S', 'V', 'G', ' ')) {
|
|
|
|
return mKeepSVG ? ots::TABLE_ACTION_PASSTHRU : ots::TABLE_ACTION_DROP;
|
|
|
|
}
|
2023-06-23 19:17:56 +00:00
|
|
|
// Preserve BASE table; harfbuzz will sanitize it before using.
|
|
|
|
if (aTag == TRUETYPE_TAG('B', 'A', 'S', 'E')) {
|
|
|
|
return ots::TABLE_ACTION_PASSTHRU;
|
|
|
|
}
|
2022-10-27 20:55:04 +00:00
|
|
|
if (mKeepColorBitmaps && (aTag == TRUETYPE_TAG('C', 'B', 'D', 'T') ||
|
|
|
|
aTag == TRUETYPE_TAG('C', 'B', 'L', 'C'))) {
|
|
|
|
return ots::TABLE_ACTION_PASSTHRU;
|
|
|
|
}
|
2020-05-22 04:47:44 +00:00
|
|
|
return ots::TABLE_ACTION_DEFAULT;
|
|
|
|
}
|
|
|
|
|
|
|
|
static size_t GuessSanitizedFontSize(size_t aLength,
|
2020-05-23 23:56:41 +00:00
|
|
|
gfxUserFontType aFontType,
|
|
|
|
bool aStrict = true) {
|
2020-05-22 04:47:44 +00:00
|
|
|
switch (aFontType) {
|
|
|
|
case GFX_USERFONT_UNKNOWN:
|
2020-05-23 23:56:41 +00:00
|
|
|
// If being permissive of unknown types, make a reasonable guess
|
|
|
|
// at how much room the sanitized font may take, if it passes. Just
|
|
|
|
// enough extra space to accomodate some growth without excessive
|
|
|
|
// bloat in case of large fonts. 1.5x is a reasonable compromise
|
|
|
|
// for growable vectors in general.
|
|
|
|
return aStrict || !aLength ? 0 : (aLength * 3) / 2;
|
2020-05-22 04:47:44 +00:00
|
|
|
case GFX_USERFONT_WOFF:
|
|
|
|
return aLength * 2;
|
|
|
|
case GFX_USERFONT_WOFF2:
|
|
|
|
return aLength * 3;
|
|
|
|
default:
|
|
|
|
return aLength;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-23 23:56:41 +00:00
|
|
|
static size_t GuessSanitizedFontSize(const uint8_t* aData, size_t aLength,
|
|
|
|
bool aStrict = true) {
|
2020-05-22 04:47:44 +00:00
|
|
|
gfxUserFontType fontType =
|
|
|
|
gfxFontUtils::DetermineFontDataType(aData, aLength);
|
2020-05-23 23:56:41 +00:00
|
|
|
return GuessSanitizedFontSize(aLength, fontType, aStrict);
|
2020-05-22 04:47:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
bool mCheckOTLTables;
|
|
|
|
bool mCheckVariationTables;
|
|
|
|
bool mKeepColorBitmaps;
|
2022-10-27 20:55:04 +00:00
|
|
|
bool mKeepSVG;
|
2020-05-22 04:47:44 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif /* GFX_OTS_UTILS_H */
|