Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

[ios] POC: implementation of a CoreText-based LocalGlyphRasterizer #10572

Merged
merged 14 commits into from
Nov 29, 2017

Conversation

ChrisLoer
Copy link
Contributor

This is an experiment in rasterizing glyphs locally using CTLineCreateWithAttributedString, for use with TinySDF.

The basics seem to work. Look at render test failures on macos or ios to see the appearance of the locally rendered glyphs.

The guess-based glyph metrics I copied over from the JS implementation don't seem to be quite right. Instead of trying to work out a better guess, I'll look into just getting the metrics directly from CoreText.

There are several TODOs before this is ready for production:

  • Provide a configuration interface that supports font descriptors
  • C++ wrappers on C interfaces, share code with image.mm
  • Extract glyph metrics
  • Build in font stack awareness?

/cc @1ec5 @boundsj

@ChrisLoer ChrisLoer added ⚠️ DO NOT MERGE Work in progress, proof of concept, or on hold text rendering iOS Mapbox Maps SDK for iOS labels Nov 27, 2017
… drawn area, better align to baseline.

Includes code to extract glyph metrics, but the results don't match anything I'd expect so I'm not using them.
@ChrisLoer
Copy link
Contributor Author

The guess-based glyph metrics I copied over from the JS implementation don't seem to be quite right. Instead of trying to work out a better guess, I'll look into just getting the metrics directly from CoreText.

I wrote code to extract glyph metrics and glyph advances, but I think I must be misunderstanding something about what the CTFontGetBoundingRectsForGlyphs function is supposed to do. For some glyphs, it returns reasonable-seeming results, but for many others, it returns an all-zero bounding box (both for the individual glyph, and for the whole single-glyph run). Even for the "reasonable" results, I think the bounding box doesn't always cover all of the pixels that get drawn (I'm just eyeballing the user-coordinate -> pixel transformation).

I ended up just tweaking the metric "guesses" to work a little better -- I draw on a 40x40px bitmap and adjust the drawing position to get the glyph more in the middle.

@ChrisLoer
Copy link
Contributor Author

/cc @lilykaiser

@@ -0,0 +1,27 @@

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing #pragma once

We also typically make sure that header files include all of the symbols they reference. Instead of defining all of the aliases in the header file, we can continue to define them where we need them.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Maybe we don't need CFHandle at all? It seems like something we could replace with a portable "unique handle holder" or maybe just std::unique_ptr with custom deleters?

Add pragma once
Move instantiations of CFHandle down to where they're used (although a few are duplicated).
In my tests so far, I have yet to get CoreText to render anything differently based on the font weight changes.
@ChrisLoer
Copy link
Contributor Author

I played around a little bit with passing a font descriptor through the portable code, but didn't end up with any ownership interface that felt right. I ended up falling back to just an optional "font family" string... which is a shame because it's so much more limited than it could be. But at least this approach will give Android/iOS/JS very similar interfaces -- and as limited as the "font family" interface is, it seems to be sufficient so far in the CJK case.

I tested loading different fonts by name by just changing the Renderer instantiation in the GLFW and macos apps. Seemed to work as expected (that is, quick visual inspection showed the font looked like a member of the family I specified). There's still no automated test for this functionality -- we would need to be able to ensure a test font was locally installed in order to build a reliable test, and I'm not sure how best to do that.

Next I'll try hooking up a darwin equivalent of the font stack/font-weight heuristics we use on JS. I think that should be pretty straightforward. After that, I'll depend on someone more experienced with the iOS SDK to help finalize the bindings.

/cc @akitchen

@ChrisLoer
Copy link
Contributor Author

I hooked up the font weights, but I'm not actually seeing any effect. For instance, I have Noto Sans Regular and Noto Sans Bold both installed locally, but when I create a font with font family "Noto Sans" and set the font-weight to .4 (Apple's constant for "bold") I get what appears to be the regular version. Trying to use the symbolic traits interface I see the same (lack of) behavior.

@ChrisLoer ChrisLoer merged this pull request into core-tinysdf Nov 29, 2017
@jfirebaugh jfirebaugh deleted the ios-tinysdf-prototype branch July 27, 2018 22:47
@chloekraw chloekraw removed the ⚠️ DO NOT MERGE Work in progress, proof of concept, or on hold label Feb 4, 2020
@1ec5
Copy link
Contributor

1ec5 commented Mar 1, 2020

I hooked up the font weights, but I'm not actually seeing any effect.

#16253 and mapbox/mapbox-gl-native-ios#189 skirt this issue by relying on Core Text’s font matching API instead of rolling our own.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
iOS Mapbox Maps SDK for iOS text rendering
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants