Git Product home page Git Product logo

Comments (5)

andersmelander avatar andersmelander commented on May 27, 2024 2

The problem is that you're only getting the metrics of the root GlyphID. What you need to do is get the metrics of each component (potentially) all the way down the tree.

I ended up taking a different approach which I like much better: Instead of passing the metric structure around, I simply implemented a GetGlyphMetric method that internally traverses the glyph tree to find the GlyphID which will supply the metric. Since it doesn't need to traverse the whole tree it's actually pretty efficient. It goes something like this:

function TRedacted.GetGlyphMetric(GlyphIndex: Word): TTrueTypeGlyphMetric;
var
  GlyphDataTable: TTrueTypeFontGlyphDataTable;

  procedure DoGetGlyphMetric(GlyphIndex: Word; var MetricIndex: Word);
  var
    Glyph: TCustomTrueTypeFontGlyphData;
    i: integer;
    CompositeGlyphData: TTrueTypeFontCompositeGlyphData;
    ComponentGlyphMetric: TTrueTypeGlyphMetric;
  begin
    Glyph := GlyphDataTable.GlyphData[GlyphIndex];

    // If glyph is a simple glyph then we will just use its index as the metric index.
    if (Glyph is TTrueTypeFontSimpleGlyphData) then
      // The default MetricIndex value has already been set by the caller.
      exit;

    // If glyph is a composite glyph, then we will either use its index or one of
    // its components index as the metric index.
    if Glyph is TTrueTypeFontCompositeGlyphData then
    begin
      // The default MetricIndex value has already been set by the caller.
      CompositeGlyphData := TTrueTypeFontCompositeGlyphData(Glyph);

      // Recursively process composite glyph components
      for i := 0 to CompositeGlyphData.GlyphCount-1 do
        if (CompositeGlyphData.Glyph[i].Flags and TRedactedCompositeGlyph.GLYF_USE_MY_METRICS <> 0) then
        begin
          // We will use the index of the component. Set MetricIndex and recurse.
          MetricIndex := CompositeGlyphData.Glyph[i].GlyphIndex;

          DoGetGlyphMetric(CompositeGlyphData.Glyph[i].GlyphIndex, MetricIndex);

          // In theory multiple components could set USE_MY_METRICS but we
          // ignore that as it doesn't make sense.
          exit;
        end;
    end;
  end;

var
  MetricIndex: Word;
  VerticalMetricsTable: TRedactedVerticalMetricsTable;
begin
  Result := Default(TTrueTypeGlyphMetric);
  GlyphDataTable := TTrueTypeFontGlyphDataTable(GetTableByTableName('glyf'));
  if (GlyphDataTable = nil) then
    exit;

  MetricIndex := GlyphIndex;
  DoGetGlyphMetric(GlyphIndex, MetricIndex);

  Result.HorizontalMetric := FHorizontalMetrics.HorizontalMetric[MetricIndex];

  VerticalMetricsTable := TRedactedVerticalMetricsTable(GetTableByTableType(TRedactedVerticalMetricsTable.GetTableType));
  if (VerticalMetricsTable <> nil) then
    Result.VerticalMetric := VerticalMetricsTable.VerticalMetric[MetricIndex];
end;

Regarding implementing point-to-point positioning and hmtx and vmtx

Point-to-point position is pretty easy and the documentation is clear on how it's done. Unfortunately, a key part of that feature is "phantom points" and the details of those seem to be completely undocumented. I know what they represent (the four "corners" of the glyph), but apart from that it's pretty much guesswork.
I have also been unable to find any glyphs that actually use this feature so I'm concentrating on more important stuff for now.

from image32.

AngusJohnson avatar AngusJohnson commented on May 27, 2024

Hopefully fixed now.

from image32.

andersmelander avatar andersmelander commented on May 27, 2024

Sorry to keep going about this but I can't see that you're doing anything at all with the hmtx struct.

Its journey starts in GetGlyphMetricsInternal where you get the metrics for the "root" glyph...

Image32/source/Img32.Text.pas

Lines 2001 to 2005 in 20a2ec6

function TFontReader.GetGlyphMetricsInternal(glyphIdx: integer;
out pathsEx: TPathsEx): TGlyphMetrics;
begin
if IsValidFontFormat and
GetGlyphHorzMetrics(glyphIdx, result.hmtx) then

...and pass it on to GetGlyphPaths:

pathsEx := GetGlyphPaths(glyphIdx, result.hmtx, result.glyf); //gets raw splines

In GetGlyphPaths you pass it on to GetCompositeGlyph:

result := GetCompositeGlyph(tbl_glyf, tbl_hmtx) else

And GetCompositeGlyph copies it to a local temporary and passes that recursively on to GetGlyphPaths, etc., etc.

Image32/source/Img32.Text.pas

Lines 1880 to 1881 in 20a2ec6

component_tbl_hmtx := tbl_hmtx;
componentPaths := GetGlyphPaths(glyphIndex, component_tbl_hmtx, component_tbl_glyf);

In GetCompositeGlyph, once GetGlyphPaths returns, you examine the composite flag and if USE_MY_METRICS is set you copy it back from the local:

Image32/source/Img32.Text.pas

Lines 1887 to 1888 in 20a2ec6

if (flag and USE_MY_METRICS <> 0) then
tbl_hmtx := component_tbl_hmtx; //(#24)

Now, in none of the above is the metrics actually updated. The structure remains unmodified from start to end.

The problem is that you're only getting the metrics of the root GlyphID. What you need to do is get the metrics of each component (potentially) all the way down the tree.

For example, move the call to GetGlyphHorzMetrics from GetGlyphMetricsInternal into GetGlyphPaths so you're getting the metrics for the glyph component and have GetCompositeGlyph update the caller's metrics if the USE_MY_METRICS flag is set. You're almost doing it and it's as if this was your meaning all along.

function TFontReader.GetCompositeGlyph(var tbl_glyf: TFontTable_Glyf;
  var tbl_hmtx: TFontTable_Hmtx): TPathsEx;
...
    component_tbl_hmtx := Default(TFontTable_Hmtx);
    componentPaths := GetGlyphPaths(glyphIndex, component_tbl_hmtx, component_tbl_glyf);
    ...
    if (flag and USE_MY_METRICS <> 0) then
      tbl_hmtx := component_tbl_hmtx;               //(#24)

from image32.

andersmelander avatar andersmelander commented on May 27, 2024

Btw, I believe the vmtx values should be copied as well. Sorry :-)

If you're planning on implementing point-to-point positioning (ARGS_ARE_XY_VALUES flag not set) at some time it might be easier to just pass the hmtx and vmtx values as "phantom-points" since you will need those for that anyway.

from image32.

AngusJohnson avatar AngusJohnson commented on May 27, 2024

Thanks again Anders for your valuable feedback.
It's been quite a while since I've closely looked at this stuff so I'm rather rusty about this now. I might look at this more closely soonish, but at the moment I'm occupied with other things, including improving the vectorization and color quantization code here.
Regarding implementing point-to-point positioning and hmtx and vmtx: if you can provide code that implements these, or links to where these are implemented elsewhere, I would of course fix this more quickly 😁🤞.

from image32.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.