1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2024 The Android Open Source Project
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker #include "src/ports/SkFontScanner_fontations_priv.h"
8*c8dee2aaSAndroid Build Coastguard Worker #include "src/ports/SkTypeface_fontations_priv.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "src/ports/fontations/src/skpath_bridge.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "src/sfnt/SkOTUtils.h"
11*c8dee2aaSAndroid Build Coastguard Worker
12*c8dee2aaSAndroid Build Coastguard Worker using namespace skia_private;
13*c8dee2aaSAndroid Build Coastguard Worker
14*c8dee2aaSAndroid Build Coastguard Worker namespace {
make_bridge_font_ref(SkData * fontData,uint32_t index)15*c8dee2aaSAndroid Build Coastguard Worker rust::Box<::fontations_ffi::BridgeFontRef> make_bridge_font_ref(SkData* fontData, uint32_t index) {
16*c8dee2aaSAndroid Build Coastguard Worker rust::Slice<const uint8_t> slice{fontData->bytes(), fontData->size()};
17*c8dee2aaSAndroid Build Coastguard Worker return fontations_ffi::make_font_ref(slice, index);
18*c8dee2aaSAndroid Build Coastguard Worker }
19*c8dee2aaSAndroid Build Coastguard Worker // TODO(drott): Remove this once SkData::MakeFromStream is able to do this itself.
make_data_avoiding_copy(SkStreamAsset * stream)20*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkData> make_data_avoiding_copy(SkStreamAsset* stream) {
21*c8dee2aaSAndroid Build Coastguard Worker if (!stream) {
22*c8dee2aaSAndroid Build Coastguard Worker return SkData::MakeEmpty();
23*c8dee2aaSAndroid Build Coastguard Worker }
24*c8dee2aaSAndroid Build Coastguard Worker if (stream->getData()) {
25*c8dee2aaSAndroid Build Coastguard Worker return stream->getData();
26*c8dee2aaSAndroid Build Coastguard Worker }
27*c8dee2aaSAndroid Build Coastguard Worker if (stream->getMemoryBase() && stream->getLength()) {
28*c8dee2aaSAndroid Build Coastguard Worker return SkData::MakeWithoutCopy(stream->getMemoryBase(), stream->getLength());
29*c8dee2aaSAndroid Build Coastguard Worker }
30*c8dee2aaSAndroid Build Coastguard Worker
31*c8dee2aaSAndroid Build Coastguard Worker return SkData::MakeFromStream(stream, stream->getLength());
32*c8dee2aaSAndroid Build Coastguard Worker }
33*c8dee2aaSAndroid Build Coastguard Worker } // namespace
34*c8dee2aaSAndroid Build Coastguard Worker
SkFontScanner_Fontations()35*c8dee2aaSAndroid Build Coastguard Worker SkFontScanner_Fontations::SkFontScanner_Fontations() {}
36*c8dee2aaSAndroid Build Coastguard Worker
~SkFontScanner_Fontations()37*c8dee2aaSAndroid Build Coastguard Worker SkFontScanner_Fontations::~SkFontScanner_Fontations() {}
38*c8dee2aaSAndroid Build Coastguard Worker
scanFile(SkStreamAsset * stream,int * numFaces) const39*c8dee2aaSAndroid Build Coastguard Worker bool SkFontScanner_Fontations::scanFile(SkStreamAsset* stream, int* numFaces) const {
40*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkData> fontData = make_data_avoiding_copy(stream);
41*c8dee2aaSAndroid Build Coastguard Worker stream->rewind();
42*c8dee2aaSAndroid Build Coastguard Worker rust::Slice<const uint8_t> slice{fontData->bytes(), fontData->size()};
43*c8dee2aaSAndroid Build Coastguard Worker ::std::uint32_t num_fonts;
44*c8dee2aaSAndroid Build Coastguard Worker if (!fontations_ffi::font_or_collection(slice, num_fonts)) {
45*c8dee2aaSAndroid Build Coastguard Worker return false;
46*c8dee2aaSAndroid Build Coastguard Worker }
47*c8dee2aaSAndroid Build Coastguard Worker *numFaces = num_fonts == 0 ? 1 : num_fonts;
48*c8dee2aaSAndroid Build Coastguard Worker return true;
49*c8dee2aaSAndroid Build Coastguard Worker }
50*c8dee2aaSAndroid Build Coastguard Worker
scanFace(SkStreamAsset * stream,int faceIndex,int * numInstances) const51*c8dee2aaSAndroid Build Coastguard Worker bool SkFontScanner_Fontations::scanFace(SkStreamAsset* stream,
52*c8dee2aaSAndroid Build Coastguard Worker int faceIndex,
53*c8dee2aaSAndroid Build Coastguard Worker int* numInstances) const {
54*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkData> fontData = make_data_avoiding_copy(stream);
55*c8dee2aaSAndroid Build Coastguard Worker rust::Box<fontations_ffi::BridgeFontRef> fontRef =
56*c8dee2aaSAndroid Build Coastguard Worker make_bridge_font_ref(fontData.get(), faceIndex);
57*c8dee2aaSAndroid Build Coastguard Worker stream->rewind();
58*c8dee2aaSAndroid Build Coastguard Worker if (!fontations_ffi::font_ref_is_valid(*fontRef)) {
59*c8dee2aaSAndroid Build Coastguard Worker return false;
60*c8dee2aaSAndroid Build Coastguard Worker }
61*c8dee2aaSAndroid Build Coastguard Worker
62*c8dee2aaSAndroid Build Coastguard Worker if (numInstances) {
63*c8dee2aaSAndroid Build Coastguard Worker *numInstances = fontations_ffi::num_named_instances(*fontRef);
64*c8dee2aaSAndroid Build Coastguard Worker }
65*c8dee2aaSAndroid Build Coastguard Worker return true;
66*c8dee2aaSAndroid Build Coastguard Worker }
67*c8dee2aaSAndroid Build Coastguard Worker
make_normalized_coords(fontations_ffi::BridgeFontRef const & bridgeFontRef,const SkFontArguments::VariationPosition & variationPosition)68*c8dee2aaSAndroid Build Coastguard Worker rust::Box<fontations_ffi::BridgeNormalizedCoords> make_normalized_coords(
69*c8dee2aaSAndroid Build Coastguard Worker fontations_ffi::BridgeFontRef const& bridgeFontRef,
70*c8dee2aaSAndroid Build Coastguard Worker const SkFontArguments::VariationPosition& variationPosition) {
71*c8dee2aaSAndroid Build Coastguard Worker // Cast is safe because of static_assert matching the structs above.
72*c8dee2aaSAndroid Build Coastguard Worker rust::Slice<const fontations_ffi::SkiaDesignCoordinate> coordinates(
73*c8dee2aaSAndroid Build Coastguard Worker reinterpret_cast<const fontations_ffi::SkiaDesignCoordinate*>(
74*c8dee2aaSAndroid Build Coastguard Worker variationPosition.coordinates),
75*c8dee2aaSAndroid Build Coastguard Worker variationPosition.coordinateCount);
76*c8dee2aaSAndroid Build Coastguard Worker return resolve_into_normalized_coords(bridgeFontRef, coordinates);
77*c8dee2aaSAndroid Build Coastguard Worker }
78*c8dee2aaSAndroid Build Coastguard Worker
scanInstance(SkStreamAsset * stream,int faceIndex,int instanceIndex,SkString * name,SkFontStyle * style,bool * isFixedPitch,AxisDefinitions * axes) const79*c8dee2aaSAndroid Build Coastguard Worker bool SkFontScanner_Fontations::scanInstance(SkStreamAsset* stream,
80*c8dee2aaSAndroid Build Coastguard Worker int faceIndex,
81*c8dee2aaSAndroid Build Coastguard Worker int instanceIndex,
82*c8dee2aaSAndroid Build Coastguard Worker SkString* name,
83*c8dee2aaSAndroid Build Coastguard Worker SkFontStyle* style,
84*c8dee2aaSAndroid Build Coastguard Worker bool* isFixedPitch,
85*c8dee2aaSAndroid Build Coastguard Worker AxisDefinitions* axes) const {
86*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkData> fontData = make_data_avoiding_copy(stream);
87*c8dee2aaSAndroid Build Coastguard Worker rust::Box<fontations_ffi::BridgeFontRef> bridgeFontFaceRef =
88*c8dee2aaSAndroid Build Coastguard Worker make_bridge_font_ref(fontData.get(), faceIndex);
89*c8dee2aaSAndroid Build Coastguard Worker stream->rewind();
90*c8dee2aaSAndroid Build Coastguard Worker if (!fontations_ffi::font_ref_is_valid(*bridgeFontFaceRef)) {
91*c8dee2aaSAndroid Build Coastguard Worker return false;
92*c8dee2aaSAndroid Build Coastguard Worker }
93*c8dee2aaSAndroid Build Coastguard Worker
94*c8dee2aaSAndroid Build Coastguard Worker if (name != nullptr) {
95*c8dee2aaSAndroid Build Coastguard Worker rust::String readFamilyName = fontations_ffi::family_name(*bridgeFontFaceRef);
96*c8dee2aaSAndroid Build Coastguard Worker *name = SkString(readFamilyName.data(), readFamilyName.size());
97*c8dee2aaSAndroid Build Coastguard Worker }
98*c8dee2aaSAndroid Build Coastguard Worker
99*c8dee2aaSAndroid Build Coastguard Worker if (isFixedPitch != nullptr) {
100*c8dee2aaSAndroid Build Coastguard Worker *isFixedPitch = false; // TODO
101*c8dee2aaSAndroid Build Coastguard Worker }
102*c8dee2aaSAndroid Build Coastguard Worker
103*c8dee2aaSAndroid Build Coastguard Worker if (style != nullptr) {
104*c8dee2aaSAndroid Build Coastguard Worker auto num = SkToInt(fontations_ffi::num_named_instances(*bridgeFontFaceRef));
105*c8dee2aaSAndroid Build Coastguard Worker if (instanceIndex > num) {
106*c8dee2aaSAndroid Build Coastguard Worker return false;
107*c8dee2aaSAndroid Build Coastguard Worker } else if (instanceIndex == 0) {
108*c8dee2aaSAndroid Build Coastguard Worker // This is the default instance
109*c8dee2aaSAndroid Build Coastguard Worker rust::Slice<const fontations_ffi::SkiaDesignCoordinate> coordinates;
110*c8dee2aaSAndroid Build Coastguard Worker rust::Box<fontations_ffi::BridgeNormalizedCoords> normalizedCoords =
111*c8dee2aaSAndroid Build Coastguard Worker resolve_into_normalized_coords(*bridgeFontFaceRef, coordinates);
112*c8dee2aaSAndroid Build Coastguard Worker fontations_ffi::BridgeFontStyle fontStyle;
113*c8dee2aaSAndroid Build Coastguard Worker if (fontations_ffi::get_font_style(*bridgeFontFaceRef, *normalizedCoords, fontStyle)) {
114*c8dee2aaSAndroid Build Coastguard Worker *style = SkFontStyle(fontStyle.weight, fontStyle.width, (SkFontStyle::Slant)fontStyle.slant);
115*c8dee2aaSAndroid Build Coastguard Worker } else {
116*c8dee2aaSAndroid Build Coastguard Worker *style = SkFontStyle::Normal();
117*c8dee2aaSAndroid Build Coastguard Worker }
118*c8dee2aaSAndroid Build Coastguard Worker } else {
119*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<SkFontArguments::VariationPosition::Coordinate[]> extractedCoords =
120*c8dee2aaSAndroid Build Coastguard Worker nullptr;
121*c8dee2aaSAndroid Build Coastguard Worker size_t numNamedInstanceCoords =
122*c8dee2aaSAndroid Build Coastguard Worker fontations_ffi::coordinates_for_shifted_named_instance_index(
123*c8dee2aaSAndroid Build Coastguard Worker *bridgeFontFaceRef,
124*c8dee2aaSAndroid Build Coastguard Worker instanceIndex << 16,
125*c8dee2aaSAndroid Build Coastguard Worker rust::cxxbridge1::Slice<fontations_ffi::SkiaDesignCoordinate>());
126*c8dee2aaSAndroid Build Coastguard Worker extractedCoords.reset(new SkFontArguments::VariationPosition::Coordinate[numNamedInstanceCoords]);
127*c8dee2aaSAndroid Build Coastguard Worker
128*c8dee2aaSAndroid Build Coastguard Worker rust::cxxbridge1::Slice<fontations_ffi::SkiaDesignCoordinate> targetSlice(
129*c8dee2aaSAndroid Build Coastguard Worker reinterpret_cast<fontations_ffi::SkiaDesignCoordinate*>(extractedCoords.get()),
130*c8dee2aaSAndroid Build Coastguard Worker numNamedInstanceCoords);
131*c8dee2aaSAndroid Build Coastguard Worker size_t retrievedNamedInstanceCoords =
132*c8dee2aaSAndroid Build Coastguard Worker fontations_ffi::coordinates_for_shifted_named_instance_index(
133*c8dee2aaSAndroid Build Coastguard Worker *bridgeFontFaceRef, faceIndex + (instanceIndex << 16), targetSlice);
134*c8dee2aaSAndroid Build Coastguard Worker if (numNamedInstanceCoords != retrievedNamedInstanceCoords) {
135*c8dee2aaSAndroid Build Coastguard Worker return false;
136*c8dee2aaSAndroid Build Coastguard Worker }
137*c8dee2aaSAndroid Build Coastguard Worker
138*c8dee2aaSAndroid Build Coastguard Worker SkFontArguments::VariationPosition variationPosition;
139*c8dee2aaSAndroid Build Coastguard Worker variationPosition.coordinateCount = numNamedInstanceCoords;
140*c8dee2aaSAndroid Build Coastguard Worker variationPosition.coordinates = extractedCoords.get();
141*c8dee2aaSAndroid Build Coastguard Worker
142*c8dee2aaSAndroid Build Coastguard Worker rust::Box<fontations_ffi::BridgeNormalizedCoords> normalizedCoords =
143*c8dee2aaSAndroid Build Coastguard Worker make_normalized_coords(*bridgeFontFaceRef, variationPosition);
144*c8dee2aaSAndroid Build Coastguard Worker fontations_ffi::BridgeFontStyle fontStyle;
145*c8dee2aaSAndroid Build Coastguard Worker if (fontations_ffi::get_font_style(*bridgeFontFaceRef, *normalizedCoords, fontStyle)) {
146*c8dee2aaSAndroid Build Coastguard Worker *style = SkFontStyle(fontStyle.weight,
147*c8dee2aaSAndroid Build Coastguard Worker fontStyle.width,
148*c8dee2aaSAndroid Build Coastguard Worker static_cast<SkFontStyle::Slant>(fontStyle.slant));
149*c8dee2aaSAndroid Build Coastguard Worker }
150*c8dee2aaSAndroid Build Coastguard Worker }
151*c8dee2aaSAndroid Build Coastguard Worker }
152*c8dee2aaSAndroid Build Coastguard Worker
153*c8dee2aaSAndroid Build Coastguard Worker if (axes != nullptr) {
154*c8dee2aaSAndroid Build Coastguard Worker rust::Box<fontations_ffi::BridgeFontRef> bridgeFontNamedInstanceRef =
155*c8dee2aaSAndroid Build Coastguard Worker make_bridge_font_ref(fontData.get(), faceIndex + (instanceIndex << 16));
156*c8dee2aaSAndroid Build Coastguard Worker stream->rewind();
157*c8dee2aaSAndroid Build Coastguard Worker auto size = SkToInt(fontations_ffi::num_axes(*bridgeFontNamedInstanceRef));
158*c8dee2aaSAndroid Build Coastguard Worker axes->reset(size);
159*c8dee2aaSAndroid Build Coastguard Worker auto variationAxes = std::make_unique<SkFontParameters::Variation::Axis[]>(size);
160*c8dee2aaSAndroid Build Coastguard Worker sk_fontations::AxisWrapper axisWrapper(variationAxes.get(), size);
161*c8dee2aaSAndroid Build Coastguard Worker auto size1 = fontations_ffi::populate_axes(*bridgeFontNamedInstanceRef, axisWrapper);
162*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(size == size1);
163*c8dee2aaSAndroid Build Coastguard Worker for (auto i = 0; i < size; ++i) {
164*c8dee2aaSAndroid Build Coastguard Worker const auto var = variationAxes[i];
165*c8dee2aaSAndroid Build Coastguard Worker (*axes)[i].fTag = var.tag;
166*c8dee2aaSAndroid Build Coastguard Worker (*axes)[i].fMinimum = var.min;
167*c8dee2aaSAndroid Build Coastguard Worker (*axes)[i].fDefault = var.def;
168*c8dee2aaSAndroid Build Coastguard Worker (*axes)[i].fMaximum = var.max;
169*c8dee2aaSAndroid Build Coastguard Worker }
170*c8dee2aaSAndroid Build Coastguard Worker }
171*c8dee2aaSAndroid Build Coastguard Worker
172*c8dee2aaSAndroid Build Coastguard Worker return true;
173*c8dee2aaSAndroid Build Coastguard Worker }
174*c8dee2aaSAndroid Build Coastguard Worker
MakeFromStream(std::unique_ptr<SkStreamAsset> stream,const SkFontArguments & args) const175*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkTypeface> SkFontScanner_Fontations::MakeFromStream(std::unique_ptr<SkStreamAsset> stream,
176*c8dee2aaSAndroid Build Coastguard Worker const SkFontArguments& args) const {
177*c8dee2aaSAndroid Build Coastguard Worker return SkTypeface_Fontations::MakeFromStream(std::move(stream), args);
178*c8dee2aaSAndroid Build Coastguard Worker }
179*c8dee2aaSAndroid Build Coastguard Worker
getFactoryId() const180*c8dee2aaSAndroid Build Coastguard Worker SkTypeface::FactoryId SkFontScanner_Fontations::getFactoryId() const {
181*c8dee2aaSAndroid Build Coastguard Worker return SkTypeface_Fontations::FactoryId;
182*c8dee2aaSAndroid Build Coastguard Worker }
183*c8dee2aaSAndroid Build Coastguard Worker
SkFontScanner_Make_Fontations()184*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<SkFontScanner> SkFontScanner_Make_Fontations() {
185*c8dee2aaSAndroid Build Coastguard Worker return std::make_unique<SkFontScanner_Fontations>();
186*c8dee2aaSAndroid Build Coastguard Worker }
187