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
|