Lazarus

Programming => Packages and Libraries => LazUtils => Topic started by: Vladimyr on January 07, 2013, 05:37:47 pm

Title: [LazFreeType] Resource Font
Post by: Vladimyr on January 07, 2013, 05:37:47 pm
hi, using FreeType in my app I'd like to load custom font from resource.
Failed to substitute resource stream instead of the file stream in FreeType
because of lots of file related code, I wrote my own function to load font
face from resource. 

Could anybody help me to insert loaded face into FreeType instance?
I have not enough experience to do it myself, but don't mind to share
my work with community.
Title: Re: [LazFreeType] Resource Font
Post by: circular on January 30, 2013, 10:06:32 pm
Hello, can you explain the modifications you propose to apply ?
Title: Re: [LazFreeType] Resource Font
Post by: Vladimyr on January 31, 2013, 03:41:08 pm
hello circular,

i'd like to add
Code: [Select]
LoadFromResource (const ResourceName: String)method into TFreeTypeFont type.

actually, this one is 90% ready (see attach on the 1st post),
still can't insert loaded object into existing TFreeTypeFont
data scructure.
Title: Re: [LazFreeType] Resource Font
Post by: circular on January 31, 2013, 08:39:39 pm
I think I get it, well, the code you propose comes from deeper FreeType units, so I suppose it should not be put directly TFreeTypeFont type.

More over, I suppose you are writing twice the loading code, which must be in some deeper FreeType units, right?
Title: Re: [LazFreeType] Resource Font
Post by: Vladimyr on February 01, 2013, 03:38:48 pm
you are correct, my code is similar to the existing code,
but that one is based onto file operations too tight, and
also separated into many small hierarchical functions.

it seems 'canonical' approach will be very time-consuming:
since i can't override functions enclosed into very depth,
i need to rewrite entire module 'from scratch'!
(i.e. EazyLazFreeType, LazFreeType and TTCache)

bypass the existing code is a 'tricky' way, but probably
is the shortest path to the goal.  :-[
Title: Re: [LazFreeType] Resource Font
Post by: circular on February 01, 2013, 03:44:25 pm
You may be right. Can you tell me where you've taken the parts that you've put together in your function ? From which files ?
Title: Re: [LazFreeType] Resource Font
Post by: Vladimyr on February 01, 2013, 06:27:17 pm
well, that's everything i learned.
when an instance of TFreeTypeFont is initializing,
the following procedures are being called
(I put module names in curved brackets):

_SetName {EazyLazFreeType.pas}
  \________UpdateFace {EazyLazFreeType.pas}
     \______TT_Open_Face {LazFreeType.pas}
        \____TT_Open_Stream {TTFile.pas}
           \__Stream_New {TTFile.pas}
            |_Stream_Activate (here are the file access operations!) {TTFile.pas}
           /__Cache_New {TTCache.pas}
           \__cache.clazz^.init {TTCache.pas}
            \_Face_Create (called indirectly, via "cache.clazz^.init") {TTObjs.pas}
             \_Cache_Create {TTCache.pas}
             |_Load_TrueType_Header * {TTLoad.pas}
             |_Load_TrueType_MaxProfile * {TTLoad.pas}
             |_Load_TrueType_Locations * {TTLoad.pas}
             |_Load_TrueType_CMap * {TTLoad.pas}
             |_Load_TrueType_CVT * {TTLoad.pas}
             |_Load_TrueType_Metrics_Header * {TTLoad.pas}
             |_Load_TrueType_Programs * {TTLoad.pas}
             |_Load_TrueType_Gasp * {TTLoad.pas}
             |_Load_TrueType_Names * {TTLoad.pas}
             |_Load_TrueType_OS2 * {TTLoad.pas}
             |_Load_TrueType_Hdmx * {TTLoad.pas}
             |_Load_TrueType_Postscript * {TTLoad}
             |_Load_TrueType_Metrics_Header * {TTLoad.pas}

* - these are the procedures I joined into LoadFromRecource function.
Each of these ones contain "TT_Seek_File", "TT_Access_Frame", etc. {TTFile.pas}

I'm shocked as tangled are these procedures!
Looks like it was ported from C, its limbs stick out of everywhere.  %)
Title: Re: [LazFreeType] Resource Font
Post by: circular on February 01, 2013, 08:26:11 pm
Yes it's a mess. I totally agree. I tried to put some it into classes, but there is still much to do.

I understand. In fact, I would like to rewrite completely the file access. I don't like those calls TT_Seek etc. outside of an object. So we could both add loading from resources, and also improve the way the library is written.

Thanks a lot for this description. It will be useful for this purpose.
Title: Re: [LazFreeType] Resource Font
Post by: Ask on February 02, 2013, 01:30:50 am
Quote
I would like to rewrite completely the file access.
If you do that, please also try to reduce the amount of range check errors --
that code is written in true C style, with buffer overruns everywhere :)
Title: Re: [LazFreeType] Resource Font
Post by: circular on February 06, 2013, 06:07:57 pm
Here is a patch for file access. It goes now through a TFreeTypeStream class, and TFreeTypeFont has a AccessFromStream function to load the font from any stream. There is a AStreamOwner parameter to specify that the stream must be freed by the font.

So for example, to load from a file, you can do that if you want :
Code: [Select]
    stream:= TFileStream.Create('arial.ttf',fmOpenRead);
    ftFont := TFreeTypeFont.Create;
    ftFont.AccessFromStream(stream,True{will be freed});

Instead of doing this :
Code: [Select]
ftFont := TFreeTypeFont.Create;
    ftFont.Name := 'arial.ttf';  [/quote]

About range check errors, I do not know what you're talking about Ask.
Title: Re: [LazFreeType] Resource Font
Post by: Vladimyr on February 06, 2013, 07:59:42 pm
unbelievable! within a week, you did that would take for me a month or even more!
(i'm coding in my free time only, but nevertheless...)
how can i thank you?!  O:-)

(i will try this patch on the upcoming weekend.)
Title: Re: [LazFreeType] Resource Font
Post by: circular on February 06, 2013, 09:12:14 pm
Cool. Give me some news when you do.  ;)
Title: Re: [LazFreeType] Resource Font
Post by: Ask on February 08, 2013, 02:21:00 pm
Committed in r40207. This have taken me some time to review -- but hey, it is a 2000-line patch :)
In general, I agree with the change and I have not found serious errors, so it seems to be ok.

Some notes:
1) The most important -- is there any tests besides the example? I would like to make sure nothing breaks.
2) You have removed comments related to thread-safety. Do you consider new code to be thread-safe?
3) Is TT_Stream type still needed?
4) The error handling is now quite convoluted, since it is a mix of exceptions and error coder.

Quote
About range check errors, I do not know what you're talking about Ask.
To see them, remove {$R-} from the beginning of the lazfreetype units and rebuild Lazarus with range check on.
Title: Re: [LazFreeType] Resource Font
Post by: circular on February 08, 2013, 04:21:12 pm
Ok.

1) Well I tested it with some files. That's all I can say.
2) Those comments were just misplaced, because I removed some procedures and functions. It is not thread safe. For example, I suppose it will not work if the font is loaded twice and is access by two streams at the same time. But I'm not sure about it. Otherwise, if the same font is used by two threads at the same time, it will not work at all, see point 3.
3) TT_Stream is used as an untyped global variable and a gate to access the stream. Basically, TT_Use_Stream gives you a typed class that you can use, but it will not work if it is already in use. To make it completely thread safe, it would be necessary to do that test in a critical section or something like that.
4) Sure. On one side there are LCL units that use exceptions, and on the other LazFreeType returns error codes. There is something to improve however, it is about the constructor, which can cause an exception, because FName <> '' is used as a hint that a file should be opened. Adding a boolean would allow to avoid this exception here.

Quote
Quote
About range check errors, I do not know what you're talking about Ask.
To see them, remove {$R-} from the beginning of the lazfreetype units and rebuild Lazarus with range check on.
I don't get any range error. Where for example ?

To go towards multi-threading, there would be two things to do :
- to ensure that the same file can be accessed by the different font objects.
- to provide a mutex instance, when TT_Use_Stream is called, which is released when TT_Done_Stream is called
Title: Re: [LazFreeType] Resource Font
Post by: Vladimyr on February 08, 2013, 05:50:18 pm
Cool. Give me some news when you do.  ;)
some hunks failed, but nothing serious.
compiled and it works!  :D

excuse me, but one question is left: can it work with BGRATextFX?

i've read the tutorial here (http://www.lazarus.freepascal.org/index.php?topic=12390.330), but didn't find how to select the font face.
it seems still using old 'Font.Name' approach, and also 'SetDefaultFreeTypeFontCollection'.

but even if i set font collection, how to select one font between the other ones?
or the font from resource stream still can be used somehow?

Committed in r40207.
very strange commit.... the patch uploaded here does not contain 'A Count'  %)
Title: Re: [LazFreeType] Resource Font
Post by: circular on February 08, 2013, 07:51:48 pm
Thanks for testing.  :)

excuse me, but one question is left: can it work with BGRATextFX?
Ok. I've updated BGRABitmap on subversion, now in TBGRAFreeTypeDrawer, you have a CreateTextEffect function.

Quote
but even if i set font collection, how to select one font between the other ones?
or the font from resource stream still can be used somehow?
Ok. Here is a patch to add a font from a stream into a font collection.

Can you give it a try ?
Title: Re: [LazFreeType] Resource Font
Post by: circular on February 08, 2013, 07:53:34 pm
@ask:

Ok now I got some range check errors, when running LazUtils with range check option.

It appears that variable types are not consistent with loading instruction from the frame buffer.
Title: Re: [LazFreeType] Resource Font
Post by: Ask on February 08, 2013, 09:22:51 pm
Quote
I tested it with some files.
Can you post your test program?

Quote
Ok. Here is a patch to add a font from a stream into a font collection.
Hm. Note that:
1) Init procedure is redundant, since class members are auto-zeroed on construction.
2) TFreeTypeFontCollection.AddStream has 90% common code with AddFile.

I could fix both problems myself, but I need a test :)

Quote
very strange commit.... the patch uploaded here does not contain 'A Count'
Sorry about that.

Title: Re: [LazFreeType] Resource Font
Post by: circular on February 09, 2013, 10:27:50 am
Here is test program for AddStream.

Note that you need to copy in timesi.ttf (Times New Roman Italic) and arial.ttf (Arial Regular).
Title: Re: [LazFreeType] Resource Font
Post by: Vladimyr on February 09, 2013, 02:59:32 pm
Finally, I got everything working.

Correct approach was to create a default font collection,
add several fonts into it from resource stream, set this
collection as default one, and select each font via
Code: [Select]
xxx.FontNamereferring to its internal name (not file name nor resource name).

Also, too many ways to draw text make things a bit complicated
for beginners. These ones are:
Code: [Select]
BGRABitmap.TextOut (...)
BGRAFreeTypeDrawer.DrawText (...)
BGRAVectorizedFontRenderer.TextOut (...)
BGRATextEffect.Draw (...)

Now I use the 4th variant, but it could be interesting to learn
the difference. What I discovered for now:
1) can draw shadow, can't use stream font;
2) can't draw shadow, can use stream font;
3) can draw shadow, can't use stream font;
4) can draw shadow, can use stream font.

Hope it will be useful to know that for somebody.
Thank you again for your inestimable work!  8)
Title: Re: [LazFreeType] Resource Font
Post by: circular on February 09, 2013, 10:42:04 pm
Hello, you're right, it's too complicated.

I've simplified by adding access to effects from the font renderer.

Now it's very simple. Here is a tutorial about it :
http://wiki.freepascal.org/BGRABitmap_tutorial_Font_rendering

I've also added explanations in BGRAText, BGRATextFX, BGRAVectorize and BGRAFreeType units.