Skip to content

Commit

Permalink
Start of variable vmtx support (VarMetrics facility not used yet)
Browse files Browse the repository at this point in the history
  • Loading branch information
skef committed Apr 11, 2024
1 parent 14bd003 commit 114f167
Show file tree
Hide file tree
Showing 16 changed files with 414 additions and 86 deletions.
2 changes: 2 additions & 0 deletions c/addfeatures/hotconv/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ add_library(hotconv OBJECT
STAT.cpp
STAT.h
uniblock.h
VarMetrics.h
VarMetrics.cpp
vmtx.cpp
vmtx.h
winansi.h
Expand Down
28 changes: 16 additions & 12 deletions c/addfeatures/hotconv/FeatParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@ void featparserParserInitialize() {
1,0,0,0,886,887,1,0,0,0,887,888,1,0,0,0,888,889,5,118,0,0,889,890,5,82,
0,0,890,891,5,125,0,0,891,137,1,0,0,0,892,895,3,140,70,0,893,895,3,4,
2,0,894,892,1,0,0,0,894,893,1,0,0,0,895,896,1,0,0,0,896,897,5,125,0,0,
897,139,1,0,0,0,898,899,7,8,0,0,899,924,5,141,0,0,900,901,7,9,0,0,901,
897,139,1,0,0,0,898,899,7,8,0,0,899,924,3,62,31,0,900,901,7,9,0,0,901,
924,5,141,0,0,902,903,5,100,0,0,903,924,3,206,103,0,904,905,5,97,0,0,
905,924,5,130,0,0,906,907,5,87,0,0,907,908,5,141,0,0,908,909,5,141,0,
0,909,910,5,141,0,0,910,911,5,141,0,0,911,912,5,141,0,0,912,913,5,141,
Expand Down Expand Up @@ -513,7 +513,7 @@ void featparserParserInitialize() {
0,1026,1027,5,125,0,0,1027,165,1,0,0,0,1028,1031,3,168,84,0,1029,1031,
3,4,2,0,1030,1028,1,0,0,0,1030,1029,1,0,0,0,1031,1032,1,0,0,0,1032,1033,
5,125,0,0,1033,167,1,0,0,0,1034,1035,7,12,0,0,1035,1036,3,196,98,0,1036,
1037,5,141,0,0,1037,169,1,0,0,0,1038,1039,5,26,0,0,1039,1043,5,51,0,0,
1037,3,62,31,0,1037,169,1,0,0,0,1038,1039,5,26,0,0,1039,1043,5,51,0,0,
1040,1044,3,172,86,0,1041,1044,5,62,0,0,1042,1044,3,200,100,0,1043,1040,
1,0,0,0,1043,1041,1,0,0,0,1043,1042,1,0,0,0,1044,1045,1,0,0,0,1045,1046,
5,27,0,0,1046,171,1,0,0,0,1047,1050,3,174,87,0,1048,1049,5,50,0,0,1049,
Expand Down Expand Up @@ -7114,12 +7114,8 @@ tree::TerminalNode* FeatParser::Os_2Context::CAP_HEIGHT() {
return getToken(FeatParser::CAP_HEIGHT, 0);
}

std::vector<tree::TerminalNode *> FeatParser::Os_2Context::NUM() {
return getTokens(FeatParser::NUM);
}

tree::TerminalNode* FeatParser::Os_2Context::NUM(size_t i) {
return getToken(FeatParser::NUM, i);
FeatParser::SingleValueLiteralContext* FeatParser::Os_2Context::singleValueLiteral() {
return getRuleContext<FeatParser::SingleValueLiteralContext>(0);
}

tree::TerminalNode* FeatParser::Os_2Context::FS_TYPE() {
Expand All @@ -7146,6 +7142,14 @@ tree::TerminalNode* FeatParser::Os_2Context::OS2_UPPER_OP_SIZE() {
return getToken(FeatParser::OS2_UPPER_OP_SIZE, 0);
}

std::vector<tree::TerminalNode *> FeatParser::Os_2Context::NUM() {
return getTokens(FeatParser::NUM);
}

tree::TerminalNode* FeatParser::Os_2Context::NUM(size_t i) {
return getToken(FeatParser::NUM, i);
}

tree::TerminalNode* FeatParser::Os_2Context::FAMILY_CLASS() {
return getToken(FeatParser::FAMILY_CLASS, 0);
}
Expand Down Expand Up @@ -7222,7 +7226,7 @@ FeatParser::Os_2Context* FeatParser::os_2() {
consume();
}
setState(899);
antlrcpp::downCast<Os_2Context *>(_localctx)->num = match(FeatParser::NUM);
antlrcpp::downCast<Os_2Context *>(_localctx)->num = singleValueLiteral();
break;
}

Expand Down Expand Up @@ -8447,8 +8451,8 @@ FeatParser::GlyphContext* FeatParser::VmtxContext::glyph() {
return getRuleContext<FeatParser::GlyphContext>(0);
}

tree::TerminalNode* FeatParser::VmtxContext::NUM() {
return getToken(FeatParser::NUM, 0);
FeatParser::SingleValueLiteralContext* FeatParser::VmtxContext::singleValueLiteral() {
return getRuleContext<FeatParser::SingleValueLiteralContext>(0);
}

tree::TerminalNode* FeatParser::VmtxContext::VERT_ORIGIN_Y() {
Expand Down Expand Up @@ -8500,7 +8504,7 @@ FeatParser::VmtxContext* FeatParser::vmtx() {
setState(1035);
glyph();
setState(1036);
match(FeatParser::NUM);
singleValueLiteral();

}
catch (RecognitionException &e) {
Expand Down
2 changes: 1 addition & 1 deletion c/addfeatures/hotconv/FeatParser.g4
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,7 @@ vmtxStatement:
;

vmtx:
( VERT_ORIGIN_Y | VERT_ADVANCE_Y ) glyph NUM
( VERT_ORIGIN_Y | VERT_ADVANCE_Y ) glyph singleValueLiteral
;

anchor:
Expand Down
9 changes: 5 additions & 4 deletions c/addfeatures/hotconv/FeatParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -1464,7 +1464,7 @@ class FeatParser : public antlr4::Parser {

class Os_2Context : public antlr4::ParserRuleContext {
public:
antlr4::Token *num = nullptr;
FeatParser::SingleValueLiteralContext *num = nullptr;
antlr4::Token *unum = nullptr;
FeatParser::GenNumContext *gnum = nullptr;
Os_2Context(antlr4::ParserRuleContext *parent, size_t invokingState);
Expand All @@ -1476,14 +1476,15 @@ class FeatParser : public antlr4::Parser {
antlr4::tree::TerminalNode *WIN_DESCENT();
antlr4::tree::TerminalNode *X_HEIGHT();
antlr4::tree::TerminalNode *CAP_HEIGHT();
std::vector<antlr4::tree::TerminalNode *> NUM();
antlr4::tree::TerminalNode* NUM(size_t i);
SingleValueLiteralContext *singleValueLiteral();
antlr4::tree::TerminalNode *FS_TYPE();
antlr4::tree::TerminalNode *FS_TYPE_v();
antlr4::tree::TerminalNode *WEIGHT_CLASS();
antlr4::tree::TerminalNode *WIDTH_CLASS();
antlr4::tree::TerminalNode *OS2_LOWER_OP_SIZE();
antlr4::tree::TerminalNode *OS2_UPPER_OP_SIZE();
std::vector<antlr4::tree::TerminalNode *> NUM();
antlr4::tree::TerminalNode* NUM(size_t i);
antlr4::tree::TerminalNode *FAMILY_CLASS();
GenNumContext *genNum();
antlr4::tree::TerminalNode *VENDOR();
Expand Down Expand Up @@ -1723,7 +1724,7 @@ class FeatParser : public antlr4::Parser {
VmtxContext(antlr4::ParserRuleContext *parent, size_t invokingState);
virtual size_t getRuleIndex() const override;
GlyphContext *glyph();
antlr4::tree::TerminalNode *NUM();
SingleValueLiteralContext *singleValueLiteral();
antlr4::tree::TerminalNode *VERT_ORIGIN_Y();
antlr4::tree::TerminalNode *VERT_ADVANCE_Y();

Expand Down
2 changes: 1 addition & 1 deletion c/addfeatures/hotconv/FeatParser.interp

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions c/addfeatures/hotconv/FeatVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1121,13 +1121,14 @@ antlrcpp::Any FeatVisitor::visitVmtx(FeatParser::VmtxContext *ctx) {
if ( stage != vExtract )
return nullptr;
GID gid = getGlyph(ctx->glyph(), false);
int16_t v = getNum<int16_t>(TOK(ctx->NUM())->getText(), 10);
VarValueRecord vvr;
getSingleValueLiteral(ctx->singleValueLiteral(), vvr);
TOK(ctx);
if ( ctx->VERT_ORIGIN_Y() != nullptr )
hotAddVertOriginY(fc->g, gid, v);
hotAddVertOriginY(fc->g, gid, vvr);
else {
assert(ctx->VERT_ADVANCE_Y() != nullptr);
hotAddVertAdvanceY(fc->g, gid, v);
hotAddVertAdvanceY(fc->g, gid, vvr);
}
return nullptr;
}
Expand Down
5 changes: 3 additions & 2 deletions c/addfeatures/hotconv/GSUB.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -418,9 +418,10 @@ void GSUB::SingleSubst::fill(GSUB &h, SubtableInfo &si) {

for (auto [t, r] : si.singles) {
auto &hotgi = h.g->glyphs[r];
if (hotgi.vAdv == SHRT_MAX) {
if (!hotgi.vAdv.isInitialized()) {
/* don't set it if it has already been set, as with vmtx overrides */
hotgi.vAdv = -(h.g->glyphs[t].hAdv);
// XXX this is wrong -- need the whole hAdv here from hmtx.
hotgi.vAdv.addValue(h.g->glyphs[t].hAdv);
}
}
}
Expand Down
194 changes: 194 additions & 0 deletions c/addfeatures/hotconv/VarMetrics.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
/* Copyright 2024 Adobe Systems Incorporated (http://www.adobe.com/). All Rights Reserved.
This software is licensed as OpenSource, under the Apache License, Version 2.0. This license is available at: http://opensource.org/licenses/Apache-2.0. */

#include "VarMetrics.h"


std::vector<Fixed> &VarMetrics::getLocationScalars(uint32_t location,
VarLocationMap &vlm) {
auto i = locationScalars.find(location);
if (i != locationScalars.end())
return i->second;

std::vector<Fixed> scalars;
auto l = vlm.getLocation(location);
assert(l != nullptr);
ivs->calcRegionScalars(logger, l->alocs, scalars);
auto s = locationScalars.insert_or_assign(location, std::move(scalars));
return s.first->second;
}

std::vector<uint16_t> &VarMetrics::getRegionIndices(uint16_t vsindex) {
auto i = regionsForVsindex.find(vsindex);
if (i != regionsForVsindex.end())
return i->second;

std::vector<uint16_t> regionIndices;
ivs->getRegionIndices(vsindex, regionIndices);
auto s = regionsForVsindex.insert_or_assign(vsindex, std::move(regionIndices));
return s.first->second;
}

float VarMetrics::blendCurrent(uint16_t vsindex, uint16_t curIndex, abfBlendArg *v) {
assert(curIndex < currentLocations.size());
uint32_t loc = currentLocations[curIndex];

auto lsi = locationScalars.find(loc);
assert(lsi != locationScalars.end());
auto &locScalars = lsi->second;
auto &regions = getRegionIndices(vsindex);

float r = v->value, fsc;
if (v->hasBlend) {
for (size_t i = 0; i < regions.size(); i++) {
assert(regions[i] < locScalars.size());
fixtopflt(locScalars[regions[i]], &fsc);
r += v->blendValues[i] * fsc;
}
}
return r;
}

static int vmetricsBeg(abfGlyphCallbacks *cb, abfGlyphInfo *info) {
cb->info = info;
VarMetrics *vm = (VarMetrics *)cb->direct_ctx;
for (auto &cs : vm->currentInstState) {
cb->direct_ctx = (void *) &cs;
abfGlyphMetricsCallbacks.beg(cb, info);
}
cb->direct_ctx = (void *) vm;
return ABF_CONT_RET;
}

static void vmetricsMoveVF(abfGlyphCallbacks *cb, abfBlendArg *x0, abfBlendArg *y0) {
VarMetrics *vm = (VarMetrics *)cb->direct_ctx;
auto vsindex = cb->info->blendInfo.vsindex;
for (size_t i = 0; i < vm->currentInstState.size(); i++) {
float x_0 = vm->blendCurrent(vsindex, i, x0);
float y_0 = vm->blendCurrent(vsindex, i, y0);
cb->direct_ctx = (void *) &vm->currentInstState[i];
abfGlyphMetricsCallbacks.move(cb, x_0, y_0);
}
cb->direct_ctx = (void *) vm;
}

static void vmetricsLineVF(abfGlyphCallbacks *cb, abfBlendArg *x1, abfBlendArg *y1) {
VarMetrics *vm = (VarMetrics *)cb->direct_ctx;
auto vsindex = cb->info->blendInfo.vsindex;
for (size_t i = 0; i < vm->currentInstState.size(); i++) {
float x_1 = vm->blendCurrent(vsindex, i, x1);
float y_1 = vm->blendCurrent(vsindex, i, y1);
cb->direct_ctx = (void *) &vm->currentInstState[i];
abfGlyphMetricsCallbacks.line(cb, x_1, y_1);
}
cb->direct_ctx = (void *) vm;
}

static void vmetricsCurveVF(abfGlyphCallbacks *cb,
abfBlendArg *x1, abfBlendArg *y1,
abfBlendArg *x2, abfBlendArg *y2,
abfBlendArg *x3, abfBlendArg *y3) {
VarMetrics *vm = (VarMetrics *)cb->direct_ctx;
auto vsindex = cb->info->blendInfo.vsindex;
for (size_t i = 0; i < vm->currentInstState.size(); i++) {
float x_1 = vm->blendCurrent(vsindex, i, x1);
float y_1 = vm->blendCurrent(vsindex, i, y1);
float x_2 = vm->blendCurrent(vsindex, i, x2);
float y_2 = vm->blendCurrent(vsindex, i, y2);
float x_3 = vm->blendCurrent(vsindex, i, x3);
float y_3 = vm->blendCurrent(vsindex, i, y3);
cb->direct_ctx = (void *) &vm->currentInstState[i];
abfGlyphMetricsCallbacks.curve(cb, x_1, y_1, x_2, y_2, x_3, y_3);
}
cb->direct_ctx = (void *) vm;
}

static void vmetricsEnd(abfGlyphCallbacks *cb) {
VarMetrics *vm = (VarMetrics *)cb->direct_ctx;
for (auto &cs : vm->currentInstState) {
cb->direct_ctx = (void *) &cs;
abfGlyphMetricsCallbacks.end(cb);
}
cb->direct_ctx = (void *) vm;
}

void VarMetrics::prepGlyphData(GID gid, const std::vector<uint32_t> locations,
VarLocationMap &vlm) {
auto gi = glyphData.find(gid);
if (gi == glyphData.end())
currentLocations = locations;
else {
currentLocations.clear();
for (auto l : locations)
if (gi->second.find(l) == gi->second.end())
currentLocations.push_back(l);
}
for (uint32_t loc : currentLocations)
getLocationScalars(loc, vlm); // Pre-load the scalars
currentInstState.resize(currentLocations.size());
static abfGlyphCallbacks glyphcb = {
(void *)this,
NULL,
NULL,
vmetricsBeg,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
vmetricsEnd,
vmetricsMoveVF,
vmetricsLineVF,
vmetricsCurveVF,
NULL
};

cfrGetGlyphByTag(cfr, gid, &glyphcb);

for (size_t i = 0; i < currentInstState.size(); i++) {
auto &is = currentInstState[i];
GlyphInstMetrics gim;
gim.bbox.left = (int16_t) is.int_mtx.left;
gim.bbox.bottom = (int16_t) is.int_mtx.bottom;
gim.bbox.right = (int16_t) is.int_mtx.right;
gim.bbox.top = (int16_t) is.int_mtx.top ;
// insert won't overwrite an existing entry, so this
// works whether there is or is not a GID entry already
auto gii = glyphData.insert({gid, {}});
gii.first->second.insert({i, gim});
}
}

VarMetrics::GlyphInstMetrics &VarMetrics::getGlyphData(GID gid,
uint32_t location,
VarLocationMap &vlm,
bool onRetry) {
auto gi = glyphData.find(gid);
if (gi == glyphData.end()) {
if (onRetry) {
logger->log(sFATAL, "Internal error: Could not load metrics data "
"for glyph %d", (int)gid);
GlyphInstMetrics fake;
return fake;
} else {
prepGlyphData(gid, location, vlm);
return getGlyphData(gid, location, vlm, true);
}
}
auto li = gi->second.find(location);
if (li == gi->second.end()) {
if (onRetry) {
logger->log(sFATAL, "Internal error: Could not load metrics data "
"for glyph %d", (int)gid);
GlyphInstMetrics fake;
return fake;
} else {
prepGlyphData(gid, location, vlm);
return getGlyphData(gid, location, vlm, true);
}
}
return li->second;
}
Loading

0 comments on commit 114f167

Please sign in to comment.