summaryrefslogtreecommitdiffstats
path: root/gfx/thebes/gfxOTSUtils.h
blob: a4e573f867f8281470ab4e30b1c6a39f4364c925 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/* -*- 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 };

  explicit gfxOTSExpandingMemoryStream(size_t initial,
                                       size_t limit = DEFAULT_LIMIT)
      : mLength(initial), mLimit(limit), mOff(0) {
    mPtr = mAlloc.Grow(nullptr, mLength);
  }

  ~gfxOTSExpandingMemoryStream() { mAlloc.Free(mPtr); }

  size_t size() override { return mLimit; }

  // 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();
    // 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();
  }

  virtual ots::TableAction GetTableAction(uint32_t aTag) override {
    // Pass through or validate OTL and Variation tables, depending on prefs.
    if ((!mCheckOTLTables && (aTag == TRUETYPE_TAG('G', 'D', 'E', 'F') ||
                              aTag == TRUETYPE_TAG('G', 'P', 'O', 'S') ||
                              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;
    }
    // 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;
    }
    if (mKeepColorBitmaps && (aTag == TRUETYPE_TAG('C', 'B', 'D', 'T') ||
                              aTag == TRUETYPE_TAG('C', 'B', 'L', 'C'))) {
      return ots::TABLE_ACTION_PASSTHRU;
    }
    return ots::TABLE_ACTION_DEFAULT;
  }

  static size_t GuessSanitizedFontSize(size_t aLength,
                                       gfxUserFontType aFontType,
                                       bool aStrict = true) {
    switch (aFontType) {
      case GFX_USERFONT_UNKNOWN:
        // 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;
      case GFX_USERFONT_WOFF:
        return aLength * 2;
      case GFX_USERFONT_WOFF2:
        return aLength * 3;
      default:
        return aLength;
    }
  }

  static size_t GuessSanitizedFontSize(const uint8_t* aData, size_t aLength,
                                       bool aStrict = true) {
    gfxUserFontType fontType =
        gfxFontUtils::DetermineFontDataType(aData, aLength);
    return GuessSanitizedFontSize(aLength, fontType, aStrict);
  }

 private:
  bool mCheckOTLTables;
  bool mCheckVariationTables;
  bool mKeepColorBitmaps;
  bool mKeepSVG;
};

#endif /* GFX_OTS_UTILS_H */