1// Copyright 2013 Google Inc. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15// Library for preprocessing fonts as part of the WOFF 2.0 conversion.
16
17#include "./transform.h"
18
19#include <complex>  // for std::abs
20
21#include "./buffer.h"
22#include "./font.h"
23#include "./glyph.h"
24#include "./table_tags.h"
25
26namespace woff2 {
27
28namespace {
29
30const int FLAG_ARG_1_AND_2_ARE_WORDS = 1 << 0;
31const int FLAG_WE_HAVE_INSTRUCTIONS = 1 << 8;
32
33void WriteBytes(std::vector<uint8_t>* out, const uint8_t* data, size_t len) {
34  if (len == 0) return;
35  size_t offset = out->size();
36  out->resize(offset + len);
37  memcpy(&(*out)[offset], data, len);
38}
39
40void WriteBytes(std::vector<uint8_t>* out, const std::vector<uint8_t>& in) {
41  for (int i = 0; i < in.size(); ++i) {
42    out->push_back(in[i]);
43  }
44}
45
46void WriteUShort(std::vector<uint8_t>* out, int value) {
47  out->push_back(value >> 8);
48  out->push_back(value & 255);
49}
50
51void WriteLong(std::vector<uint8_t>* out, int value) {
52  out->push_back((value >> 24) & 255);
53  out->push_back((value >> 16) & 255);
54  out->push_back((value >> 8) & 255);
55  out->push_back(value & 255);
56}
57
58void Write255UShort(std::vector<uint8_t>* out, int value) {
59  if (value < 253) {
60    out->push_back(value);
61  } else if (value < 506) {
62    out->push_back(255);
63    out->push_back(value - 253);
64  } else if (value < 762) {
65    out->push_back(254);
66    out->push_back(value - 506);
67  } else {
68    out->push_back(253);
69    out->push_back(value >> 8);
70    out->push_back(value & 0xff);
71  }
72}
73
74// Glyf table preprocessing, based on
75// GlyfEncoder.java
76// but only the "sbbox" and "cbbox" options are supported.
77class GlyfEncoder {
78 public:
79  explicit GlyfEncoder(int num_glyphs)
80      : sbbox_(false), cbbox_(true), n_glyphs_(num_glyphs) {
81    bbox_bitmap_.resize(((num_glyphs + 31) >> 5) << 2);
82  }
83
84  bool Encode(int glyph_id, const Glyph& glyph) {
85    if (glyph.composite_data_size > 0) {
86      WriteCompositeGlyph(glyph_id, glyph);
87    } else if (glyph.contours.size() > 0) {
88      WriteSimpleGlyph(glyph_id, glyph);
89    } else {
90      WriteUShort(&n_contour_stream_, 0);
91    }
92    return true;
93  }
94
95  void GetTransformedGlyfBytes(std::vector<uint8_t>* result) {
96    WriteLong(result, 0);  // version
97    WriteUShort(result, n_glyphs_);
98    WriteUShort(result, 0);  // index_format, will be set later
99    WriteLong(result, n_contour_stream_.size());
100    WriteLong(result, n_points_stream_.size());
101    WriteLong(result, flag_byte_stream_.size());
102    WriteLong(result, glyph_stream_.size());
103    WriteLong(result, composite_stream_.size());
104    WriteLong(result, bbox_bitmap_.size() + bbox_stream_.size());
105    WriteLong(result, instruction_stream_.size());
106    WriteBytes(result, n_contour_stream_);
107    WriteBytes(result, n_points_stream_);
108    WriteBytes(result, flag_byte_stream_);
109    WriteBytes(result, glyph_stream_);
110    WriteBytes(result, composite_stream_);
111    WriteBytes(result, bbox_bitmap_);
112    WriteBytes(result, bbox_stream_);
113    WriteBytes(result, instruction_stream_);
114  }
115
116 private:
117  void WriteInstructions(const Glyph& glyph) {
118    Write255UShort(&glyph_stream_, glyph.instructions_size);
119    WriteBytes(&instruction_stream_,
120               glyph.instructions_data, glyph.instructions_size);
121  }
122
123  void WriteSimpleGlyph(int glyph_id, const Glyph& glyph) {
124    int num_contours = glyph.contours.size();
125    WriteUShort(&n_contour_stream_, num_contours);
126    if (sbbox_) {
127      WriteBbox(glyph_id, glyph);
128    }
129    // TODO: check that bbox matches, write bbox if not
130    for (int i = 0; i < num_contours; i++) {
131      Write255UShort(&n_points_stream_, glyph.contours[i].size());
132    }
133    int lastX = 0;
134    int lastY = 0;
135    for (int i = 0; i < num_contours; i++) {
136      int num_points = glyph.contours[i].size();
137      for (int j = 0; j < num_points; j++) {
138        int x = glyph.contours[i][j].x;
139        int y = glyph.contours[i][j].y;
140        int dx = x - lastX;
141        int dy = y - lastY;
142        WriteTriplet(glyph.contours[i][j].on_curve, dx, dy);
143        lastX = x;
144        lastY = y;
145      }
146    }
147    if (num_contours > 0) {
148      WriteInstructions(glyph);
149    }
150  }
151
152  void WriteCompositeGlyph(int glyph_id, const Glyph& glyph) {
153    WriteUShort(&n_contour_stream_, -1);
154    if (cbbox_) {
155      WriteBbox(glyph_id, glyph);
156    }
157    WriteBytes(&composite_stream_,
158               glyph.composite_data,
159               glyph.composite_data_size);
160    if (glyph.have_instructions) {
161      WriteInstructions(glyph);
162    }
163  }
164
165  void WriteBbox(int glyph_id, const Glyph& glyph) {
166    bbox_bitmap_[glyph_id >> 3] |= 0x80 >> (glyph_id & 7);
167    WriteUShort(&bbox_stream_, glyph.x_min);
168    WriteUShort(&bbox_stream_, glyph.y_min);
169    WriteUShort(&bbox_stream_, glyph.x_max);
170    WriteUShort(&bbox_stream_, glyph.y_max);
171  }
172
173  void WriteTriplet(bool on_curve, int x, int y) {
174    int abs_x = std::abs(x);
175    int abs_y = std::abs(y);
176    int on_curve_bit = on_curve ? 0 : 128;
177    int x_sign_bit = (x < 0) ? 0 : 1;
178    int y_sign_bit = (y < 0) ? 0 : 1;
179    int xy_sign_bits = x_sign_bit + 2 * y_sign_bit;
180    if (x == 0 && abs_y < 1280) {
181      flag_byte_stream_.push_back(on_curve_bit +
182                                  ((abs_y & 0xf00) >> 7) + y_sign_bit);
183      glyph_stream_.push_back(abs_y & 0xff);
184    } else if (y == 0 && abs_x < 1280) {
185      flag_byte_stream_.push_back(on_curve_bit + 10 +
186                                  ((abs_x & 0xf00) >> 7) + x_sign_bit);
187      glyph_stream_.push_back(abs_x & 0xff);
188    } else if (abs_x < 65 && abs_y < 65) {
189      flag_byte_stream_.push_back(on_curve_bit + 20 +
190                                  ((abs_x - 1) & 0x30) +
191                                  (((abs_y - 1) & 0x30) >> 2) +
192                                  xy_sign_bits);
193      glyph_stream_.push_back((((abs_x - 1) & 0xf) << 4) | ((abs_y - 1) & 0xf));
194    } else if (abs_x < 769 && abs_y < 769) {
195      flag_byte_stream_.push_back(on_curve_bit + 84 +
196                                  12 * (((abs_x - 1) & 0x300) >> 8) +
197                                  (((abs_y - 1) & 0x300) >> 6) + xy_sign_bits);
198      glyph_stream_.push_back((abs_x - 1) & 0xff);
199      glyph_stream_.push_back((abs_y - 1) & 0xff);
200    } else if (abs_x < 4096 && abs_y < 4096) {
201      flag_byte_stream_.push_back(on_curve_bit + 120 + xy_sign_bits);
202      glyph_stream_.push_back(abs_x >> 4);
203      glyph_stream_.push_back(((abs_x & 0xf) << 4) | (abs_y >> 8));
204      glyph_stream_.push_back(abs_y & 0xff);
205    } else {
206      flag_byte_stream_.push_back(on_curve_bit + 124 + xy_sign_bits);
207      glyph_stream_.push_back(abs_x >> 8);
208      glyph_stream_.push_back(abs_x & 0xff);
209      glyph_stream_.push_back(abs_y >> 8);
210      glyph_stream_.push_back(abs_y & 0xff);
211    }
212  }
213
214  std::vector<uint8_t> n_contour_stream_;
215  std::vector<uint8_t> n_points_stream_;
216  std::vector<uint8_t> flag_byte_stream_;
217  std::vector<uint8_t> composite_stream_;
218  std::vector<uint8_t> bbox_bitmap_;
219  std::vector<uint8_t> bbox_stream_;
220  std::vector<uint8_t> glyph_stream_;
221  std::vector<uint8_t> instruction_stream_;
222  bool sbbox_;
223  bool cbbox_;
224  int n_glyphs_;
225};
226
227}  // namespace
228
229bool TransformGlyfAndLocaTables(Font* font) {
230  Font::Table* transformed_glyf = &font->tables[kGlyfTableTag ^ 0x80808080];
231  Font::Table* transformed_loca = &font->tables[kLocaTableTag ^ 0x80808080];
232
233  int num_glyphs = NumGlyphs(*font);
234  GlyfEncoder encoder(num_glyphs);
235  for (int i = 0; i < num_glyphs; ++i) {
236    Glyph glyph;
237    const uint8_t* glyph_data;
238    size_t glyph_size;
239    if (!GetGlyphData(*font, i, &glyph_data, &glyph_size) ||
240        (glyph_size > 0 && !ReadGlyph(glyph_data, glyph_size, &glyph))) {
241      return FONT_COMPRESSION_FAILURE();
242    }
243    encoder.Encode(i, glyph);
244  }
245  encoder.GetTransformedGlyfBytes(&transformed_glyf->buffer);
246
247  const Font::Table* head_table = font->FindTable(kHeadTableTag);
248  if (head_table == NULL || head_table->length < 52) {
249    return FONT_COMPRESSION_FAILURE();
250  }
251  transformed_glyf->buffer[7] = head_table->data[51];  // index_format
252
253  transformed_glyf->tag = kGlyfTableTag ^ 0x80808080;
254  transformed_glyf->length = transformed_glyf->buffer.size();
255  transformed_glyf->data = transformed_glyf->buffer.data();
256
257  transformed_loca->tag = kLocaTableTag ^ 0x80808080;
258  transformed_loca->length = 0;
259  transformed_loca->data = NULL;
260
261  return true;
262}
263
264} // namespace woff2
265