summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/platform/fonts/opentype/font_format_check.cc
blob: e1710f6bb2a031c95e07b9e5285308f657fac5f7 (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
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "third_party/blink/renderer/platform/fonts/opentype/font_format_check.h"

// Include HarfBuzz to have a cross-platform way to retrieve table tags without
// having to rely on the platform being able to instantiate this font format.
#include <hb.h>

#include "base/sys_byteorder.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
#include "third_party/harfbuzz-ng/utils/hb_scoped.h"
#include "third_party/skia/include/core/SkTypeface.h"

namespace blink {

namespace {

FontFormatCheck::COLRVersion determineCOLRVersion(
    const FontFormatCheck::TableTagsVector& table_tags,
    const hb_face_t* face) {
  const hb_tag_t kCOLRTag = HB_TAG('C', 'O', 'L', 'R');

  // Only try to read version if header size is sufficient.
  // https://docs.microsoft.com/en-us/typography/opentype/spec/colr#header
  const unsigned int kMinCOLRHeaderSize = 14;
  if (table_tags.size() && table_tags.Contains(kCOLRTag) &&
      table_tags.Contains(HB_TAG('C', 'P', 'A', 'L'))) {
    HbScoped<hb_blob_t> table_blob(hb_face_reference_table(face, kCOLRTag));
    if (hb_blob_get_length(table_blob.get()) < kMinCOLRHeaderSize)
      return FontFormatCheck::COLRVersion::kNoCOLR;

    unsigned required_bytes_count = 2u;
    const char* colr_data =
        hb_blob_get_data(table_blob.get(), &required_bytes_count);
    if (required_bytes_count < 2u)
      return FontFormatCheck::COLRVersion::kNoCOLR;

    uint16_t colr_version =
        base::NetToHost16(*reinterpret_cast<const uint16_t*>(colr_data));

    if (colr_version == 0)
      return FontFormatCheck::COLRVersion::kCOLRV0;
    else if (colr_version == 1)
      return FontFormatCheck::COLRVersion::kCOLRV1;
  }
  return FontFormatCheck::COLRVersion::kNoCOLR;
}

}  // namespace

FontFormatCheck::FontFormatCheck(sk_sp<SkData> sk_data) {
  HbScoped<hb_blob_t> font_blob(hb_blob_create(
      reinterpret_cast<const char*>(sk_data->bytes()), sk_data->size(),
      HB_MEMORY_MODE_READONLY, nullptr, nullptr));
  HbScoped<hb_face_t> face(hb_face_create(font_blob.get(), 0));

  unsigned table_count = 0;
  table_count = hb_face_get_table_tags(face.get(), 0, nullptr, nullptr);
  table_tags_.resize(table_count);
  if (!hb_face_get_table_tags(face.get(), 0, &table_count, table_tags_.data()))
    table_tags_.resize(0);

  colr_version_ = determineCOLRVersion(table_tags_, face.get());
}

bool FontFormatCheck::IsVariableFont() {
  return table_tags_.size() && table_tags_.Contains(HB_TAG('f', 'v', 'a', 'r'));
}

bool FontFormatCheck::IsCbdtCblcColorFont() {
  return table_tags_.size() &&
         table_tags_.Contains(HB_TAG('C', 'B', 'D', 'T')) &&
         table_tags_.Contains(HB_TAG('C', 'B', 'L', 'C'));
}

bool FontFormatCheck::IsColrCpalColorFontV0() {
  return colr_version_ == COLRVersion::kCOLRV0;
}

bool FontFormatCheck::IsColrCpalColorFontV1() {
  return colr_version_ == COLRVersion::kCOLRV1;
}

bool FontFormatCheck::IsSbixColorFont() {
  return table_tags_.size() && table_tags_.Contains(HB_TAG('s', 'b', 'i', 'x'));
}

bool FontFormatCheck::IsCff2OutlineFont() {
  return table_tags_.size() && table_tags_.Contains(HB_TAG('C', 'F', 'F', '2'));
}

bool FontFormatCheck::IsColorFont() {
  return IsCbdtCblcColorFont() || IsColrCpalColorFont() || IsSbixColorFont();
}

FontFormatCheck::VariableFontSubType FontFormatCheck::ProbeVariableFont(
    sk_sp<SkTypeface> typeface) {
  if (!typeface->getTableSize(
          SkFontTableTag(SkSetFourByteTag('f', 'v', 'a', 'r'))))
    return VariableFontSubType::kNotVariable;

  if (typeface->getTableSize(
          SkFontTableTag(SkSetFourByteTag('C', 'F', 'F', '2'))))
    return VariableFontSubType::kVariableCFF2;
  return VariableFontSubType::kVariableTrueType;
}

}  // namespace blink