Skip to content

Commit

Permalink
Prepare possibility of cacheing table data.
Browse files Browse the repository at this point in the history
  • Loading branch information
robmeek committed May 18, 2024
2 parents 27fda6f + a6b7f3b commit ba8c5eb
Show file tree
Hide file tree
Showing 34 changed files with 477 additions and 257 deletions.
2 changes: 1 addition & 1 deletion spec/fonthx/opentype/tables/CFFSpec.hx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class CFFSpec extends buddy.BuddySuite {

private function getTableAsArray(table:Table):Array<Int> {
var tt = new TrueTypeFileWriter();
table.write(tt);
table.getBytes(tt);
var bytes = tt.getBytes();
var b = [];
for (i in 0...bytes.length) {
Expand Down
1 change: 1 addition & 0 deletions src/fonthx/examples/pixelfonter/PixelFonter.hx
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ class PixelFonter {
buildOptions.useSubroutinesInCFF = true;
buildOptions.useFixedCoordinatesInCFF = opts.floatingPointCoords;
buildOptions.includeSVG = opts.includeSVG;
//buildOptions.includeDeprecatedKERNTable = true;
buildOptions.includeCOLR = opts.includeCOLR;

var bytes = OpenTypeBuilder.build(font, opts.format == 'ttf' ? TrueType : CFF, buildOptions);
Expand Down
2 changes: 1 addition & 1 deletion src/fonthx/model/font/PathProperties.hx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class PathProperties {

public function new() {
fill = RGBAColor.BLACK;
stroke = null;
stroke = 0;
opacity = 1;
}
}
170 changes: 170 additions & 0 deletions src/fonthx/model/geom/Matrix.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
package fonthx.model.geom;

import fonthx.model.geom.Point;

class Matrix {

public var a:Float;
public var b:Float;
public var c:Float;
public var d:Float;
public var tx:Float;
public var ty:Float;

public function new(a:Float = 1, b:Float = 0, c:Float = 0, d:Float = 1, tx:Float = 0, ty:Float = 0) {
this.a = a;
this.b = b;
this.c = c;
this.d = d;
this.tx = tx;
this.ty = ty;
}

public function clone():Matrix {
return new Matrix (a, b, c, d, tx, ty);
}

public function concat(m:Matrix):Void {
var a1 = a * m.a + b * m.c;
b = a * m.b + b * m.d;
a = a1;
var c1 = c * m.a + d * m.c;
d = c * m.b + d * m.d;
c = c1;
var tx1 = tx * m.a + ty * m.c + m.tx;
ty = tx * m.b + ty * m.d + m.ty;
tx = tx1;
}

public function copyFrom(other:Matrix):Void {
this.a = other.a;
this.b = other.b;
this.c = other.c;
this.d = other.d;
this.tx = other.tx;
this.ty = other.ty;
}

public function createBox(scaleX:Float, scaleY:Float, rotation:Float = 0, tx:Float = 0, ty:Float = 0):Void {
a = scaleX;
d = scaleY;
b = rotation;
this.tx = tx;
this.ty = ty;
}

public function createGradientBox(width:Float, height:Float, rotation:Float = 0, tx:Float = 0, ty:Float = 0):Void {
a = width / 1638.4;
d = height / 1638.4;
if (rotation != 0.0) {
var cos = Math.cos(rotation);
var sin = Math.sin(rotation);
b = sin * d;
c = -sin * a;
a *= cos;
d *= cos;
} else {
b = c = 0;
}
this.tx = tx + width / 2;
this.ty = ty + height / 2;
}

public function identity():Void {
a = 1;
b = 0;
c = 0;
d = 1;
tx = 0;
ty = 0;
}

public function invert():Matrix {
var norm = a * d - b * c;
if (norm == 0) {
a = b = c = d = 0;
tx = -tx;
ty = -ty;
} else {
norm = 1.0 / norm;
var a1 = d * norm;
d = a * norm;
a = a1;
b *= -norm;
c *= -norm;
var tx1 = -a * tx - c * ty;
ty = -b * tx - d * ty;
tx = tx1;
}
return this;
}

public function mult(m:Matrix):Matrix {
var result = new Matrix ();
result.a = a * m.a + b * m.c;
result.b = a * m.b + b * m.d;
result.c = c * m.a + d * m.c;
result.d = c * m.b + d * m.d;
result.tx = tx * m.a + ty * m.c + m.tx;
result.ty = tx * m.b + ty * m.d + m.ty;
return result;
}

public function rotate(angle:Float):Void {
var cos = Math.cos(angle);
var sin = Math.sin(angle);
var a1 = a * cos - b * sin;
b = a * sin + b * cos;
a = a1;
var c1 = c * cos - d * sin;
d = c * sin + d * cos;
c = c1;
var tx1 = tx * cos - ty * sin;
ty = tx * sin + ty * cos;
tx = tx1;
}

public function scale(x:Float, y:Float):Void {
a *= x;
b *= y;
c *= x;
d *= y;
tx *= x;
ty *= y;
}

public function setRotation(angle:Float, scale:Float = 1):Void {
a = Math.cos(angle) * scale;
c = Math.sin(angle) * scale;
b = -c;
d = a;
}

public function setTo(a:Float, b:Float, c:Float, d:Float, tx:Float, ty:Float):Void {
this.a = a;
this.b = b;
this.c = c;
this.d = d;
this.tx = tx;
this.ty = ty;
}

public function toString():String {
return "(a=" + a + ", b=" + b + ", c=" + c + ", d=" + d + ", tx=" + tx + ", ty=" + ty + ")";
}

public function transformPoint(point:Point):Point {
// todo do we always want to create a new point here?
return new Point(point.x * a + point.y * c + tx, point.x * b + point.y * d + ty);
}

public function deltaTransformPoint(point:Point):Point {
return new Point(point.x * a + point.y * c, point.x * b + point.y * d);
}

public function translate(x:Float, y:Float):Void {
tx += x;
ty += y;
}

}
10 changes: 6 additions & 4 deletions src/fonthx/model/geom/Path.hx
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,18 @@ class Path {
bounds = new Rectangle(p.x, p.y);
} else {
if (!Math.isNaN(p.x)) {
if (p.x > bounds.x) {
if (p.x > bounds.right) {
bounds.right = p.x;
} else {
}
if (p.x < bounds.left) {
bounds.left = p.x;
}
}
if (!Math.isNaN(p.y)) {
if (p.y > bounds.y) {
if (p.y > bounds.bottom) {
bounds.bottom = p.y;
} else {
}
if (p.y < bounds.top) {
bounds.top = p.y;
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/fonthx/model/geom/Point.hx
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ class Point {
type == other.type;
}

public function transform(mtx:Matrix):Point {
return new Point(x * mtx.a + y * mtx.c + mtx.tx, x * mtx.b + y * mtx.d + mtx.ty);
}

/**
* Get a string representation of this object
*/
Expand Down
29 changes: 23 additions & 6 deletions src/fonthx/model/geom/Rectangle.hx
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@ package fonthx.model.geom;

class Rectangle {

public var x:Float;
public var y:Float;
public var width:Float;
public var height:Float;
public var top (get, set):Float;
public var topLeft (get, set):Point;
public var bottom (get, set):Float;
public var bottomRight (get, set):Point;
public var height:Float;
public var left (get, set):Float;
public var right (get, set):Float;
public var size (get, set):Point;
public var top (get, set):Float;
public var topLeft (get, set):Point;
public var width:Float;
public var x:Float;
public var y:Float;

public function new(x:Float = 0, y:Float = 0, width:Float = 0, height:Float = 0):Void {
this.x = x;
Expand Down Expand Up @@ -80,6 +80,23 @@ class Rectangle {
return new Rectangle (x0, y0, x1 - x0, y1 - y0);
}

public function transform(mtx:Matrix):Rectangle {
var p1 = topLeft.transform(mtx);
var p2 = bottomRight.transform(mtx);
return new Rectangle(p1.x, p1.y, p2.x - p1.x, p2.y - p1.y);
}

public function normalize():Void {
if (width < 0) {
x = x + width;
width = Math.abs(width);
}
if (height < 0) {
y = y + width;
height = Math.abs(height);
}
}

// Getters & Setters

private function get_bottom() { return y + height; }
Expand Down
20 changes: 8 additions & 12 deletions src/fonthx/opentype/OpenTypeBuilder.hx
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ class OpenTypeBuilder {
numTables++;
var writer = new TrueTypeFileWriter(); // todo need a factory for this (DI)
trace('Writing ${table.tag}'); // todo control verbosity
table.write(writer);
writer.writeBytes(table.getBytes());
table.length = writer.getPosition(); // store actual not padded length
writer.pad();
byteBlocks[tag] = writer.getBytes();
Expand All @@ -172,14 +172,10 @@ class OpenTypeBuilder {
}

// write the table directory
var writer = new TrueTypeFileWriter();
ttf.getTable(Table.TDIR).write(writer);
byteBlocks[Table.TDIR] = writer.getBytes();
byteBlocks[Table.TDIR] = ttf.getTable(Table.TDIR).getBytes();

// write the font header
writer = new TrueTypeFileWriter();
ttf.getTable(Table.SFNT).write(writer);
byteBlocks[Table.SFNT] = writer.getBytes();
byteBlocks[Table.SFNT] = ttf.getTable(Table.SFNT).getBytes();

// assemble the byte blocks into entire font “file”
var b:BytesBuffer = new BytesBuffer();
Expand All @@ -198,18 +194,17 @@ class OpenTypeBuilder {
bytes.set(offset + 1, (csa >>> 16) & 0xFF);
bytes.set(offset + 2, (csa >>> 8) & 0xFF);
bytes.set(offset + 3, csa & 0xFF);

return bytes;
}

private static function createFontHeader(fnt:IFont, format:FontFileFormat):FontHeader {
var head = new FontHeader();
var now = Date.now();
head.setFormat(format)
.setCreated(Utils.getMillisSince1904(now))
.setModified(Utils.getMillisSince1904(now))
.setVersion('${fnt.majorVersion}.${fnt.minorVersion}')
.setEmSquare(fnt.emSquare)
.setCreated(Utils.getMillisSince1904(now))
.setModified(Utils.getMillisSince1904(now))
.setVersion('${fnt.majorVersion}.${fnt.minorVersion}')
.setEmSquare(fnt.emSquare)
;
// calculate bounds
var bounds = null;
Expand Down Expand Up @@ -364,6 +359,7 @@ class OpenTypeBuilder {

private static function createNamingTable(fnt:IFont, options:BuildOptions):NamingTable {
var table = new NamingTable();
trace("Creating Naming table");
for (encoding in options.namingEncodings) {
var addRecord = function(key, content) { table.addRecord(key, content, encoding); } // shorthand

Expand Down
3 changes: 2 additions & 1 deletion src/fonthx/opentype/cff/CFF.hx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class CFF extends Table {
super(Table.CFF);
}

override public function write(tt:ITrueTypeWriter) {
override public function getBytes():Bytes {

// NAME INDEX (single entry only)
createNameIndex();
Expand Down Expand Up @@ -123,6 +123,7 @@ class CFF extends Table {
for (sectionKey in sectionOrder) {
tt.writeBytes(sections.get(sectionKey));
}
return tt.getBytes();
}

public function createHeader() {
Expand Down
17 changes: 12 additions & 5 deletions src/fonthx/opentype/glyph/CompositeGlyphDescription.hx
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package fonthx.opentype.glyph;

import fonthx.model.geom.Rectangle;
import haxe.io.Bytes;
import fonthx.opentype.writers.TrueTypeFileWriter;
import fonthx.model.font.IFont;
import fonthx.model.font.IContourGlyph;
import fonthx.opentype.writers.ITrueTypeWriter;
Expand Down Expand Up @@ -40,16 +43,20 @@ class CompositeGlyphDescription {
// Bit 12: The composite is designed not to have the component offset scaled. Ignored if ARGS_ARE_XY_VALUES is not set.
public static var UNSCALED_COMPONENT_OFFSET:Int = 0x1000;

private var tt:TrueTypeFileWriter;

public function new() {
tt = new TrueTypeFileWriter();
}

public function write(tt:ITrueTypeWriter, glyph:IContourGlyph, font:IFont) {

public function write(glyph:IContourGlyph, font:IFont):Bytes {
tt.markPosition();
var bounds = glyph.getBounds();
if (bounds == null) {
bounds = new Rectangle();
}
// write glyph header – todo this could be shared with SimpleGlyphDescription
tt
.writeSHORT(-1)
tt.writeSHORT(-1)
.writeSHORT(Std.int(bounds.left))
.writeSHORT(Std.int(bounds.top))
.writeSHORT(Std.int(bounds.right))
Expand Down Expand Up @@ -96,8 +103,8 @@ class CompositeGlyphDescription {

}
}

tt.pad(true);
return tt.getBytes();
}


Expand Down
Loading

0 comments on commit ba8c5eb

Please sign in to comment.