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