Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ofTrueTypeFont feature discussion #1131

Open
ofTheo opened this issue Mar 31, 2012 · 25 comments
Open

ofTrueTypeFont feature discussion #1131

ofTheo opened this issue Mar 31, 2012 · 25 comments

Comments

@ofTheo
Copy link
Member

ofTheo commented Mar 31, 2012

This is a feature discussion issue for what should be added / changed to ofTTF.
Would be great to get some eyes on this from @vtron @ofZach @arturoc and anyone with thoughts on the matter.

TextAreas:

  • Fit text to a box
  • Handle overflow ( ie either truncate or resize box height )
  • non ragged options
  • could textAreas work with both ofTTF and ofDrawBitmapString ? abstract text formatting?

Alignment:

  • Left align a string
  • Right align
  • Center
  • Top align
  • Base align

Spacing:

  • Kerning
  • Leading / line height

Loading:

  • Allow for loading a font up to a max size for drawing at different sizes.
  • Allow for selection and loading of specific sizes within one object. ie: myFont.setCurrentSize(12);
  • Font family's / sets ? Bold, Italic etc?

Drawing:

  • Allow for drawing font at different sizes. Scale font as needed.

Formatting:

  • Could we somehow allow a string to have different colors, sizes. Right now it is a pain to change colors or sizes.
  • would this be replicating basic html or another approach? maybe better as an addon?

Info:

  • Ability to get the x and y position of the nth character in the string? useful maybe for cursor or selection?

Update:
-Underline
-Render rect behind text ( a la what @kylemcdonald added to ofDrawBitmapString)
-Scale type to fit a rect + keep aspect ratio
-Crazy: text along a path :)

@ofZach
Copy link
Contributor

ofZach commented Mar 31, 2012

maybe something that scaled type to fit a rect? (we also could use a max rect in rect function that preserves aspect ratio if we don't have it... I write that constantly).

a draw from center, top left corner or baseline left mode - like OF_RECTMODE_CENTER. For doing rotated type, this could be helpful.

simple layout for mutiple words (ie, wrapping, justification).

@ofTheo
Copy link
Member Author

ofTheo commented Mar 31, 2012

@ofZach the align stuff we have in there. I think also the wrapping justification is in there or is that something else?
I added the scale type to fix rect.

@vtron would be great if you could take a look at this too.

@bilderbuchi
Copy link
Member

sry, I don't know why I recommended reserving the second post. was thinking of something else w.r.t. forums, I now realize. must've been some mental blackout. :-P

@roymacdonald
Copy link
Member

when using ofTrueTypeFont::drawString(stringstring s, float x, float y) the x and y coordinates correspond to the LOWER Left corner of the text. When rendering a single line it might be ok but when rendering a string with several lines it becomes awkward as this coordinates correspond to the baseline left of the first line. Besides this being awkward I think it would be much more consistent with the rest of OF if the top left corner is used as the coordinate at which is drawn.
Maybe having the option to switch which mode to use could be good. i.e, OF_DRAW_STRING_LEFT_TOP, OF_DRAW_STRING_LEFT_BASELINE, and extending it to OF_DRAW_STRING_CENTER_TOP, OF_DRAW_STRING_RIGHT
_TOP....

@vtron
Copy link

vtron commented Apr 2, 2012

Yes this is definitely an issue...I think that having a choice between the two is the optimal solution. The biggest issue with top left is that it will change based on the height of different characters (type starts from the baseline with ascenders and descenders in free type) so we might ahve to set a static height.

I have a lot of this in the works/done already, hoping to have something to put up soon that should give us a good jumping off point...have had a lot of stuff going on so have been quiet but should have some stuff to add shortly.

One of the main things I would also like to get in there would be texture atlases vs textures for each glyph, could save a lot of memory on iOS.

@ofZach
Copy link
Contributor

ofZach commented Apr 2, 2012

@vtron -- good to see you in the discussion! I was thinking top left = baseline + line height, in order to not have it shift as you say if the string is xyz or lkj... ie, the top left corner would be on the baseline of the above line if you were looking...

for example, here: http://imgur.com/dL3aY the top left of "one two three" is where the box is, on the baseline of the above line.

@roymacdonald
Copy link
Member

there is already a lineHeight variable that is set when the font is loaded, so changing from top to baseline is just as simple as adding or not this var to the possition to be drawn.
i can make this changes if it's ok with you.

@roymacdonald
Copy link
Member

@ofZach take a look to a branch in my OF fork called "feature-TTFDrawingPos". the two font examples in examples/graphics are modified so to switch between the two different string drawing modes (TOP and BASELINE).

@kylemcdonald
Copy link
Contributor

here's a link to the commit @roymacdonald is talking about roymacdonald@146bf24

@roymacdonald
Copy link
Member

Thanks kyle!
I should have posted the link to my commit at the begininng.

Roy Macdonald
8248-8478

On 03-04-2012, at 15:40, Kyle McDonald
reply@reply.github.com
wrote:

here's a link to the commit @roymacdonald is talking about roymacdonald@146bf24


Reply to this email directly or view it on GitHub:
#1131 (comment)

@bakercp
Copy link
Member

bakercp commented Apr 3, 2012

Hi Theo, I added kerning (at least as much as you can get from freetype -- no GPOS), and many of the items you noted in your in your initial post. I'll make sure all of my changes are linked here later this evening.

@bakercp
Copy link
Member

bakercp commented Apr 4, 2012

Here is a handful of ofFont related stuff I have been working on. It is not complete, but you can tell where I'm headed. bakercp@0ba9359

The remaining thing I need to figure out is a data structure that is something like a "text block". The goal of this data structure would be that you could feed a string and a bounding rectangle (or other arbitrary convex closed ofPath shape) and it would give you all of the lines broken appropriately. The text block would allow access to individual glyph positions for easier animation and and could be rendered quickly without reformatting each time. Returning a block like this would prevent the draw methods from doing line breaking, etc every time it is rendered (which it does now).

Regarding justification vertical and horizontal -- it's all pretty straight forward once you have lines broken with the exception of full justification. Full justification (that looks somewhat decent) is not trivial (i.e. if you want more than a typical look of expanding the inter word spaces to make the line fit). I was looking into a Knuth-Plask style algorithm for line breaking, but I'm not sure if it's worth the effort for really nice full justification (which may be why Processing has also avoided it for so long). It's still an open question in my mind. My current line breaking algorithm works pretty well.

Kerning is also in there, a new approach to font Settings (inspired by ofFbo, etc) that enables much more flexible glyph generation. One thing to note is that freetype only accesses the normal kerning tables and not the GPOS tables (http://www.freetype.org/freetype2/docs/tutorial/step2.html). Many modern fonts almost exclusively use GPOS for kerning and really can only be used well in a with a pretty sophisticated layout engine (like Pango / ICU), which is probably outside of the scope for the core ofFont class.

Anyway, I'm very happy to continue work on this or combine efforts with others. I am working on some text layout projects now and needed some of this functionality and hoped to share it at some point when it is a bit more polished.

Cheers,
Christopher

@kylemcdonald
Copy link
Contributor

@bakercp this looks incredible, it really does address a ton of the issues theo brings up!

@vtron can you spend some time looking at @bakercp's updates, testing all the features rigorously and preparing to get them into the core?

@ofTheo and @ofZach it would also be awesome, if you have a chance, to look over the commit above from @bakercp and see if you have any suggestions for different ways of accomplishing this, as far as the interface goes. personally, the ofFbo::Settings approach seems right on to me!

@bakercp
Copy link
Member

bakercp commented Apr 5, 2012

Hi all, I'm continuing to polish this -- I'll post any changes here. Basically my immediate todo list is:

  • Figure out a simplified and flexible "text block" data structure
  • Finish implementing the alignment code
  • Finish a bit of the demo code

So, don't spend too much time hacking on the commit above just yet as I still have a bunch of cleanup. More soon.

@ofTheo
Copy link
Member Author

ofTheo commented Apr 22, 2012

honestly I think ofTTF needs a complete re-write :)

I like the idea of ofFont @bakercp, I think like ofSoundPlayer etc ofFont could be a more general class and we could have a new ofTTF as a swappable engine of sorts ( like ofFmodSoundPlayer, etc ), which ofFont would use to extract the font information.

Might be interesting to bounce around some pseduo code via pastbin or gist on how we could structure ofFont.

@bakercp
Copy link
Member

bakercp commented Apr 22, 2012

I've got an almost complete rewrite that moves in this direction to propose here shortly. I'll be posting it soon.

@bakercp
Copy link
Member

bakercp commented Apr 22, 2012

It's got unicode support, selectable character sets, kerning, more sophisticated layout (even inside concave polygons!) text on a line, etc. Anyway, more soon.

@ofTheo would this complete rewrite still use freetype as its engine? or would you propose engaging the platform specific font managers?

@ofTheo
Copy link
Member Author

ofTheo commented Apr 22, 2012

ahh interesting - I hadn't thought of that.
I think for now maybe FT but with the possibility of using different font apis in the future.

very excited to see your re-write!
:)

@bakercp
Copy link
Member

bakercp commented May 13, 2012

Just wanted to ping here. Getting very close to finishing this.

@ofTheo
Copy link
Member Author

ofTheo commented May 14, 2012

great - looking forward to it!! :)

@kylemcdonald
Copy link
Contributor

ok, now it's starting to get crazy -- here's another rendition: https://github.com/sosolimited/ofxSoso/blob/master/src/ofxSosoTrueTypeFont.h

@bakercp
Copy link
Member

bakercp commented May 27, 2012

@ofTheo So, a few things to check out:

https://github.com/bakercp/ofxUnicode

This package is core to all of my packages. Basically, it provides simple method for dealing with Unicode. It currently combines a lot of POCO::Unicode support with the better UTF8 iteration provided by UTF8CPP (http://utfcpp.sourceforge.net/). POCO is able to iterate through UTF8 text via POCO::TextIterator, but its iterator is unidirectional, which is insufficient for things like hyphenators. Liblinebreak below has its own unidirectional utf8 iterator in the library.

Just by way of review, I wrote myself a long comment about what this library is actually doing here https://github.com/bakercp/ofxUnicode/blob/master/src/ofTextConverter.cpp It's very rough, but may be a good addition to the wikipedia articles on the topic and this page http://www.joelonsoftware.com/articles/Unicode.html which is a must read.

I have been bumping into some major limitations with this current fusion of UTF8CPP when it comes to layout. Initially I avoided the massive (and extremely comprehensive) ICU library (http://site.icu-project.org/). But, I just got it running in a different branch of ofxUnicode and the static code footprint is only about 16MB, and you get a ton of features with that -- probably the most comprehensive in the world. ICU also includes linebreakers, bidi (bidirectional text) algorithms and a rudimentary (but decent) text layout engine that can tap into our existing freetype system. More on that shortly.

https://github.com/bakercp/ofxFont

https://github.com/bakercp/ofxHyphenator

This is simply layout candy. It implements the classic hyphenation algorithm invented ages ago.

http://www.tug.org/docs/liang/ and http://en.wikipedia.org/wiki/Hyphenation_algorithm

The main work here was to free the existing libhyphenate (the only c/c++ implementation I could find) it from glib (it used glib for UTF8 iteration) and add static/object support for the required language files. I did this to prevent oF users from having to drop the data files in a data directory. It's kind of the same situation as a haar tracker -- it likes to load its text files. There is an example project that generates the static language headers and rolls them up into a base64 encoded-stringified strings. It's fancy.

https://github.com/bakercp/ofxLinebreaker

ofxLinebreaker is an implementation of Unicode's own linebreaking standard. This is important for text wrapping, filling boxes, shapes, etc. In most linebreakers (like Processing, etc) lines are simply broken at spaces, line feeds, and in a worse case of a box being too small, words are just hacked in half. Of course, there are ideal places to break lines, "ok" places to break lines and places were breaking a line will destroy the meaning of a word/phrase line. Thus, the Unicode standard attends to the international pitfalls of linebreaking.

One point of note -- the ICU library also implements this on its own. So, if ofxUnicode moves to ICU, then that this would be dropped in order to reduce the numer of external libs.

// and some path tools that are not directly related, but somewhat
https://github.com/bakercp/ofxClipper

This doesn't include much about my current layout research, but I'll post on that shortly or share it @ the mtg.

@bakercp
Copy link
Member

bakercp commented May 27, 2012

So a few things regarding layout.

First international text compatible layout happens on a number of different levels. Usually the tools look like this:

  • Prepare the text for rendering by applying type normalization according to the unicode standards (i.e replacing characters with ligatures, etc). ICU does this well.
  • Text is represented in byte format in a logical order, but sometimes displayed from right to left (i.e. RTL -- e.g. hebrew, etc). Thus a BIDI algorithm (a bidirectional text algorithm) can prepare the array logically ordered text for RTL rendering by reordering according to the Unicode standard. ICU does this, but the more popular library is called FRIBIDI http://fribidi.org/. FRIBIDI is everywhere.
  • After BIDI processing the text must be "shaped". This is the process of laying out text according to kerning, font size, offsets, and a whole pile of other Unicode standards. This has been done in various ways in the past -- including a layout engine built into ICU, but the new universal standard is becoming something called HarfBuzz http://www.freedesktop.org/wiki/Software/HarfBuzz -- I know -- it's crazy name, but everyone (including Pango, Google, etc) is adopting it. Harfbuzz hooks into ICU for Unicode support and can hook into any Font rasterization lib (namely Freetype) to access kerning information, glyph sizes, etc. It is pretty amazing actually.
  • Finally, there is the process of rendering everything to the screen. This is the part that I believe we need to roll ourselves for openFrameworks. The reason we need to roll it ourselves (and not use something like Pango) is because by our very nature, we need deeper level access to glyphs, paths, etc. I want to be able to experiment with the aesthetics of rendering. I do not want to experiment with the rules of Unicode layout. This is where ofxFont really steps in and allows us to do things like path filling, drawing along a curve, text effects, outlining, etc in the style of oF.

There are some other issues that I have not come to terms with quite yet -- including the ideas of an ofFontManager to manage fonts, create and cache glyphs on the fly (currently, like Processing, my current implementation rasterizes a limited character set via https://github.com/bakercp/ofxFont/blob/master/src/ofCharacterSet.h but ultimately, I think it should just happen on the fly, automatically cache and uncache the data, etc. Harfbuzz actually takes care of a lot of this stuff via its (already existing) Freetype bindings.

Anyway ... that's my story for the moment. I'm trying to fix up the ofxFont demo and it should be up in a minute.

@bakercp
Copy link
Member

bakercp commented May 27, 2012

If you just can't get enough of this stuff, here's an article by one of the big players in the FLOSS text internationalization / layout unicode effort http://behdad.org/text/. The actual harfbuzz library is being actively updated now and compiles and works just fine.

@bakercp
Copy link
Member

bakercp commented May 27, 2012

Just fixed a little ofFont example the demos the framesetter and "line" creation.

https://github.com/bakercp/ofxFont

Just for full disclosure, I'm modeling the layout engine (i.e. framesetters, typesetters, etc) after Apple's coretext. Not using their code, but their approach seems to be pretty common across typesetting solutions (libcinder basically glues each platform's text layout stuff together and uses object divisions similar to apple's coretext).

More on the purpose of objects like:

ofFormattedText, ofFramesetter, ofTextFrame, ofTextLayout, ofTextLine, ofTextRun, ofTypesetter, etc.

http://en.wikipedia.org/wiki/Core_Text

Nice pictures are here too:

https://developer.apple.com/library/mac/#documentation/StringsTextFonts/Conceptual/CoreText_Programming/Overview/Overview.html

@bakercp bakercp changed the title ofTTF feature discussion ofTrueTypeFont feature discussion May 23, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants