blob: b8ea64dfd6690ef9bac2a0fa482b42b467e3e74e [file] [log] [blame]
/*
* Copyright 2023 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "include/core/SkData.h"
#include "include/core/SkFontMetrics.h"
#include "src/core/SkFontPriv.h"
#include "src/ports/SkTypeface_fontations.h"
#include "src/ports/fontations/src/skpath_bridge.h"
namespace {
sk_sp<SkData> streamToData(const std::unique_ptr<SkStreamAsset>& font_data) {
// TODO(drott): From a stream this causes a full read/copy. Make sure
// we can instantiate this directly from the decompressed buffer that
// Blink has after OTS and woff2 decompression.
font_data->rewind();
return SkData::MakeFromStream(font_data.get(), font_data->getLength());
}
rust::Box<::fontations_ffi::BridgeFontRef> make_bridge_font_ref(sk_sp<SkData> fontData,
uint32_t index) {
rust::Slice<const uint8_t> slice{fontData->bytes(), fontData->size()};
return fontations_ffi::make_font_ref(slice, index);
}
} // namespace
SkTypeface_Fontations::SkTypeface_Fontations(std::unique_ptr<SkStreamAsset> font_data,
uint32_t ttcIndex)
: SkTypeface(SkFontStyle(), true)
, fFontData(streamToData(font_data))
, fTtcIndex(ttcIndex)
, fBridgeFontRef(make_bridge_font_ref(fFontData, fTtcIndex)) {}
int SkTypeface_Fontations::onGetUPEM() const {
return fontations_ffi::units_per_em_or_zero(*fBridgeFontRef);
}
void SkTypeface_Fontations::onGetFamilyName(SkString* familyName) const {
rust::String readFamilyName = fontations_ffi::family_name(*fBridgeFontRef);
*familyName = SkString(readFamilyName.data(), readFamilyName.size());
}
bool SkTypeface_Fontations::onGetPostScriptName(SkString* postscriptName) const {
rust::String readPsName;
if (fontations_ffi::postscript_name(*fBridgeFontRef, readPsName)) {
*postscriptName = SkString(readPsName.data(), readPsName.size());
return true;
}
return false;
}
void SkTypeface_Fontations::onCharsToGlyphs(const SkUnichar* chars,
int count,
SkGlyphID glyphs[]) const {
sk_bzero(glyphs, count * sizeof(glyphs[0]));
for (int i = 0; i < count; ++i) {
glyphs[i] = fontations_ffi::lookup_glyph_or_zero(*fBridgeFontRef, chars[i]);
}
}
int SkTypeface_Fontations::onCountGlyphs() const {
return fontations_ffi::num_glyphs(*fBridgeFontRef);
}
void SkTypeface_Fontations::onFilterRec(SkScalerContextRec* rec) const {
rec->setHinting(SkFontHinting::kNone);
}
class SkrifaLocalizedStrings : public SkTypeface::LocalizedStrings {
public:
SkrifaLocalizedStrings(
rust::Box<::fontations_ffi::BridgeLocalizedStrings> bridge_localized_strings)
: fBridgeLocalizedStrings(std::move(bridge_localized_strings)) {}
bool next(SkTypeface::LocalizedString* localized_string) override {
fontations_ffi::BridgeLocalizedName localizedName;
if (!fontations_ffi::localized_name_next(*fBridgeLocalizedStrings, localizedName)) {
return false;
}
localized_string->fString = SkString(localizedName.string.data(), localizedName.string.size());
localized_string->fLanguage =
SkString(localizedName.language.data(), localizedName.language.size());
return true;
}
private:
rust::Box<::fontations_ffi::BridgeLocalizedStrings> fBridgeLocalizedStrings;
};
SkTypeface::LocalizedStrings* SkTypeface_Fontations::onCreateFamilyNameIterator() const {
return new SkrifaLocalizedStrings(fontations_ffi::get_localized_strings(*fBridgeFontRef));
}
class SkFontationsScalerContext : public SkScalerContext {
public:
SkFontationsScalerContext(sk_sp<SkTypeface_Fontations> face,
const SkScalerContextEffects& effects,
const SkDescriptor* desc)
: SkScalerContext(face, effects, desc)
, fBridgeFontRef(static_cast<SkTypeface_Fontations*>(this->getTypeface())
->getBridgeFontRef()) {
fRec.getSingleMatrix(&fMatrix);
this->forceGenerateImageFromPath();
}
protected:
bool generateAdvance(SkGlyph* glyph) override {
SkVector scale;
SkMatrix remainingMatrix;
if (!glyph ||
!fRec.computeMatrices(
SkScalerContextRec::PreMatrixScale::kVertical, &scale, &remainingMatrix)) {
return false;
}
float x_advance = 0.0f;
x_advance = fontations_ffi::advance_width_or_zero(
fBridgeFontRef, scale.y(), glyph->getGlyphID());
// TODO(drott): y-advance?
const SkVector advance = remainingMatrix.mapXY(x_advance, SkFloatToScalar(0.f));
glyph->fAdvanceX = SkScalarToFloat(advance.fX);
glyph->fAdvanceY = SkScalarToFloat(advance.fY);
return true;
}
void generateMetrics(SkGlyph* glyph, SkArenaAlloc*) override {
glyph->fMaskFormat = fRec.fMaskFormat;
glyph->zeroMetrics();
this->generateAdvance(glyph);
// Always generates from paths, so SkScalerContext::makeGlyph will figure the bounds.
}
void generateImage(const SkGlyph&) override { SK_ABORT("Should have generated from path."); }
bool generatePath(const SkGlyph& glyph, SkPath* path) override {
SkVector scale;
SkMatrix remainingMatrix;
if (!fRec.computeMatrices(
SkScalerContextRec::PreMatrixScale::kVertical, &scale, &remainingMatrix)) {
return false;
}
fontations_ffi::SkPathWrapper pathWrapper;
if (!fontations_ffi::get_path(
fBridgeFontRef, glyph.getGlyphID(), scale.y(), pathWrapper)) {
return false;
}
*path = std::move(pathWrapper).into_inner();
*path = path->makeTransform(remainingMatrix);
return true;
}
void generateFontMetrics(SkFontMetrics* out_metrics) override {
fontations_ffi::Metrics metrics =
fontations_ffi::get_skia_metrics(fBridgeFontRef, fMatrix.getScaleY());
out_metrics->fTop = -metrics.top;
out_metrics->fAscent = -metrics.ascent;
out_metrics->fDescent = -metrics.descent;
out_metrics->fBottom = -metrics.bottom;
out_metrics->fLeading = -metrics.leading;
out_metrics->fAvgCharWidth = metrics.avg_char_width;
out_metrics->fMaxCharWidth = metrics.max_char_width;
out_metrics->fXMin = metrics.x_min;
out_metrics->fXMax = metrics.x_max;
out_metrics->fXHeight = -metrics.x_height;
out_metrics->fCapHeight = -metrics.cap_height;
out_metrics->fFlags = 0;
// TODO(drott): Is it necessary to transform metrics with remaining parts of matrix?
}
private:
SkMatrix fMatrix;
sk_sp<SkData> fFontData = nullptr;
const fontations_ffi::BridgeFontRef& fBridgeFontRef;
};
std::unique_ptr<SkStreamAsset> SkTypeface_Fontations::onOpenStream(int* ttcIndex) const {
*ttcIndex = fTtcIndex;
return std::make_unique<SkMemoryStream>(fFontData);
}
std::unique_ptr<SkScalerContext> SkTypeface_Fontations::onCreateScalerContext(
const SkScalerContextEffects& effects, const SkDescriptor* desc) const {
return std::make_unique<SkFontationsScalerContext>(
sk_ref_sp(const_cast<SkTypeface_Fontations*>(this)), effects, desc);
}