123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383 |
- /* 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 <stdlib.h>
- #include <limits>
- #include "./buffer.h"
- #include "./store_bytes.h"
- namespace woff2 {
- static const int32_t kFLAG_ONCURVE = 1;
- static const int32_t kFLAG_XSHORT = 1 << 1;
- static const int32_t kFLAG_YSHORT = 1 << 2;
- static const int32_t kFLAG_REPEAT = 1 << 3;
- static const int32_t kFLAG_XREPEATSIGN = 1 << 4;
- static const int32_t kFLAG_YREPEATSIGN = 1 << 5;
- static const int32_t kFLAG_OVERLAP_SIMPLE = 1 << 6;
- static const int32_t kFLAG_ARG_1_AND_2_ARE_WORDS = 1 << 0;
- static const int32_t kFLAG_WE_HAVE_A_SCALE = 1 << 3;
- static const int32_t kFLAG_MORE_COMPONENTS = 1 << 5;
- static const int32_t kFLAG_WE_HAVE_AN_X_AND_Y_SCALE = 1 << 6;
- static const int32_t kFLAG_WE_HAVE_A_TWO_BY_TWO = 1 << 7;
- static const int32_t kFLAG_WE_HAVE_INSTRUCTIONS = 1 << 8;
- bool ReadCompositeGlyphData(Buffer* buffer, Glyph* glyph) {
- glyph->have_instructions = false;
- glyph->composite_data = buffer->buffer() + buffer->offset();
- size_t start_offset = buffer->offset();
- uint16_t flags = 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;
- size_t arg_size = 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;
- }
- bool ReadGlyph(const uint8_t* data, size_t len, Glyph* glyph) {
- Buffer buffer(data, len);
- int16_t num_contours;
- 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.
- uint16_t last_point_index = 0;
- for (int i = 0; i < num_contours; ++i) {
- uint16_t point_index;
- if (!buffer.ReadU16(&point_index)) {
- return FONT_COMPRESSION_FAILURE();
- }
- uint16_t num_points = 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.
- std::vector<std::vector<uint8_t> > flags(num_contours);
- {
- uint8_t flag = 0;
- uint8_t flag_repeat = 0;
- for (int i = 0; i < num_contours; ++i) {
- flags[i].resize(glyph->contours[i].size());
- for (size_t j = 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;
- }
- }
- }
- if (!flags.empty() && !flags[0].empty()) {
- glyph->overlap_simple_flag_set = (flags[0][0] & kFLAG_OVERLAP_SIMPLE);
- }
- // Read the x coordinates.
- int prev_x = 0;
- for (int i = 0; i < num_contours; ++i) {
- for (size_t j = 0; j < glyph->contours[i].size(); ++j) {
- uint8_t flag = flags[i][j];
- if (flag & kFLAG_XSHORT) {
- // single byte x-delta coord value
- uint8_t x_delta;
- if (!buffer.ReadU8(&x_delta)) {
- return FONT_COMPRESSION_FAILURE();
- }
- int sign = (flag & kFLAG_XREPEATSIGN) ? 1 : -1;
- glyph->contours[i][j].x = prev_x + sign * x_delta;
- } else {
- // double byte x-delta coord value
- int16_t x_delta = 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.
- int prev_y = 0;
- for (int i = 0; i < num_contours; ++i) {
- for (size_t j = 0; j < glyph->contours[i].size(); ++j) {
- uint8_t flag = flags[i][j];
- if (flag & kFLAG_YSHORT) {
- // single byte y-delta coord value
- uint8_t y_delta;
- if (!buffer.ReadU8(&y_delta)) {
- return FONT_COMPRESSION_FAILURE();
- }
- int sign = (flag & kFLAG_YREPEATSIGN) ? 1 : -1;
- glyph->contours[i][j].y = prev_y + sign * y_delta;
- } else {
- // double byte y-delta coord value
- int16_t y_delta = 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 {
- void StoreBbox(const Glyph& glyph, size_t* offset, uint8_t* dst) {
- Store16(glyph.x_min, offset, dst);
- Store16(glyph.y_min, offset, dst);
- Store16(glyph.x_max, offset, dst);
- Store16(glyph.y_max, offset, dst);
- }
- void StoreInstructions(const Glyph& glyph, size_t* offset, uint8_t* dst) {
- Store16(glyph.instructions_size, offset, dst);
- StoreBytes(glyph.instructions_data, glyph.instructions_size, offset, dst);
- }
- bool StoreEndPtsOfContours(const Glyph& glyph, size_t* offset, uint8_t* dst) {
- int end_point = -1;
- for (const auto& contour : 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;
- }
- bool StorePoints(const Glyph& glyph, size_t* offset,
- uint8_t* dst, size_t dst_size) {
- int previous_flag = -1;
- int repeat_count = 0;
- int last_x = 0;
- int last_y = 0;
- size_t x_bytes = 0;
- size_t y_bytes = 0;
- // Store the flags and calculate the total size of the x and y coordinates.
- for (const auto& contour : glyph.contours) {
- for (const auto& point : contour) {
- int flag = point.on_curve ? kFLAG_ONCURVE : 0;
- if (previous_flag == -1 && glyph.overlap_simple_flag_set) {
- // First flag needs to have overlap simple bit set.
- flag = flag | kFLAG_OVERLAP_SIMPLE;
- }
- int dx = point.x - last_x;
- int dy = 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 == previous_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;
- previous_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.
- size_t x_offset = *offset;
- size_t y_offset = *offset + x_bytes;
- last_x = 0;
- last_y = 0;
- for (const auto& contour : glyph.contours) {
- for (const auto& point : contour) {
- int dx = point.x - last_x;
- int dy = 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
- bool StoreGlyph(const Glyph& glyph, uint8_t* dst, size_t* dst_size) {
- size_t offset = 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
|