[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: font substitution
From: |
Yen-Ju Chen |
Subject: |
Re: font substitution |
Date: |
Tue, 7 Aug 2007 10:11:43 -0700 |
On 8/7/07, Fred Kiefer <fredkiefer@gmx.de> wrote:
> OK, so here is a reworked version of this patch. I had to fix the
> coveredCharacterSet method of ftfont to get this working. So it may not
> be possible for you to actually check this code. What I would like to
> get from the mailing list is a short review, if you agree that this code
> is fast enough to be included.
> There are a few noteworthy changes to Alexander's patch. I set the
> substitution font directly as the new font for the character. I am not
> sure, if this is compatible with what Apple does. This patch also tries
> to find a substitution by looking at all available fonts. This may be
> really slow, when it fails. It will also result in the character sets
> for all fonts being cached. I am not sure, if we really want this,
> perhaps we should do this caching only for the fonts in preferredFontNames?
>
> As you can see, I am still not that sure about this patch.
If speed is the concern,
I would say caching only preferredFontNames is enough.
Because OS X ship their own fonts for each language,
I believe they can cache such information in advance for each language
and only fallback when all the defaults font fails, which hardly happens.
I also wonder whether fonts have language information inside.
If so, we can actually have a table of glyph range of each language
and only match language instead of each glyph.
That would be much faster.
And I believe that there is hardly a font supporting
only half of the glyphs for a language.
In another word, if a font has 'A', it must have [A-Z][a-z][0-9].
In that case, we only need to look at the unicode table
and pick probably 2 glyphs for each language
and use them to check the font.
Yen-Ju
>
> Cheers,
> Fred
>
>
> static NSString *lastFont = nil;
> static NSCharacterSet *lastSet = nil;
> static NSMutableDictionary *cachedCSets = nil;
>
> - (NSFont*)_substituteFontWithName: (NSString*)fontName font:
> (NSFont*)baseFont
> {
> // FIXME: Catch case were baseFont is nil
> return [NSFont fontWithName: fontName matrix: [baseFont matrix]];
> }
>
> - (NSFont*)_substituteFontFor: (unichar)uchar font: (NSFont*)baseFont
> fromList: (NSArray *)fonts
> {
> unsigned int count;
> unsigned int i;
>
> count = [fonts count];
> for (i = 0; i < count; i++)
> {
> NSFont *newFont;
> NSString *fName;
> NSCharacterSet *newSet;
>
> fName = [fonts objectAtIndex: i];
> newSet = [cachedCSets objectForKey: fName];
> if (newSet == nil)
> {
> newFont = [self _substituteFontWithName: fName font: baseFont];
> newSet = [newFont coveredCharacterSet];
> if (newSet != nil)
> {
> [cachedCSets setObject: newSet forKey: fName];
> }
> }
> else
> {
> newFont = nil;
> }
>
> if ([newSet characterIsMember: uchar])
> {
> ASSIGN(lastFont, fName);
> ASSIGN(lastSet, newSet);
> if (newFont != nil)
> {
> return newFont;
> }
> else
> {
> return [self _substituteFontWithName: fName font:
> baseFont];
> }
> }
> }
>
> return nil;
> }
>
> - (NSFont*)_substituteFontFor: (unichar)uchar font: (NSFont*)baseFont
> {
> NSFont *subFont;
>
> // Caching one font may lead to the selected substitution font not being
> // from the prefered list, although there is one there with this
> character.
> if (lastSet && [lastSet characterIsMember: uchar])
> {
> return [self _substituteFontWithName: lastFont font: baseFont];
> }
>
> if (cachedCSets == nil)
> {
> cachedCSets = [NSMutableDictionary new];
> }
>
> subFont = [self _substituteFontFor: uchar font: baseFont fromList:
> [NSFont preferredFontNames]];
> if (subFont != nil)
> {
> return subFont;
> }
>
> subFont = [self _substituteFontFor: uchar font: baseFont fromList:
> [[NSFontManager sharedFontManager] availableFonts]];
> if (subFont != nil)
> {
> return subFont;
> }
>
> return nil;
> }
>
> - (void) fixFontAttributeInRange: (NSRange)range
> {
> NSString *string;
> NSFont *font;
> NSCharacterSet *charset = nil;
> NSRange fontRange = NSMakeRange(NSNotFound, 0);
> unsigned int i;
> unsigned int lastMax;
> unsigned int start;
> unichar chars[64];
> CREATE_AUTORELEASE_POOL(pool);
>
> if (NSMaxRange (range) > [self length])
> {
> [NSException raise: NSRangeException
> format: @"RangeError in method -fixFontAttributeInRange: "];
> }
> // Check for each character if it is supported by the
> // assigned font
>
> /*
> Note that this needs to be done on a script basis. Per-character checks
> are difficult to do at all, don't give reasonable results, and would have
> really poor performance.
> */
> string = [self string];
> lastMax = range.location;
> start = lastMax;
> for (i = range.location; i < NSMaxRange(range); i++)
> {
> unichar uchar;
>
> if (i >= lastMax)
> {
> unsigned int dist;
>
> start = lastMax;
> dist = MIN(64, NSMaxRange(range) - start);
> lastMax = start + dist;
> [string getCharacters: chars range: NSMakeRange(start, dist)];
> }
> uchar = chars[i - start];
>
> if (!NSLocationInRange(i, fontRange))
> {
> font = [self attribute: NSFontAttributeName
> atIndex: i
> effectiveRange: &fontRange];
> charset = [font coveredCharacterSet];
> }
>
> if (charset != nil && ![charset characterIsMember: uchar])
> {
> // Find a replacement font
> NSFont *subFont;
>
> subFont = [self _substituteFontFor: uchar font: font];
> if (subFont != nil)
> {
> // Set substitution font permanently
> [self addAttribute: NSFontAttributeName
> value: subFont
> range: NSMakeRange(i, 1)];
> }
> }
> }
>
> RELEASE(pool);
> }
>
>
> Yen-Ju Chen wrote:
> > On 8/5/07, Fred Kiefer <fredkiefer@gmx.de> wrote:
> >> Hi Rob,
> >>
> >> there was a reason why Alexander was reluctant at that time to add this
> >> patch to the main branch of GNUstep. This is a very expensive operation
> >> that we are doing for every change of a string and it isn't even optimised.
> >> I would kindly ask you to measure the time it take to perform text
> >> operations on a reasonable large file with and without this patch in
> >> place (Where all the characters are available in the assigned font).
> >> Only when we are sure this change wont slow GNUstep down too much,
> >> should we apply it. There are already some people complaining about the
> >> slowness of GNUstep and I don't want to make things harder for them.
> >>
> >> What would be even better is to come up with a highly optimized version
> >> of this patch. For example cache for all substitution fonts the
> >> supported character set and check that instead of creating each font in
> >> turn for each character that gets checked. Also the substitutions fonts
> >> should not come from a separate user setting instead we should take he
> >> preferred fonts first and if that fails check all available fonts (This
> >> can be really slow without a cache!). Another small optimisation could
> >> be to remember the last match and to try that font first the next time
> >> we are missing a character. And in the fixFontAttributeInRange: method
> >> we could get the characters more efficiently and reuse the same font for
> >> its effective range.
> >> The method used here to check if a font is valid for a character
> >> glyphForCharacter: is an extension that only exists for the art backend.
> >> We would need to replace it with coveredCharacterSet and implement that
> >> method for all backends.
> >>
> >> I really would love to integrate this patch and as you can see I spend
> >> some time thinking about it.
> >
> > I think -coveredCharacterSet work mostly on art backend,
> > which use FreeType functions.
> > I believe the same thing can be done with Cairo by retrieving
> > FT_Face from cairo_scaled_font_t (?).
> > But for short term solution, if any of above-mentioned methods are
> > unavailable, ex in cairo backend, it can just fall back to do nothing
> > as current implementation.
> > I do meet some issues of -coveredCharacterSet with some fonts, though.
> >
> > Yen-Ju
> >
> >> Cheers
> >> Fred
> >>
> >> foobix@comcast.net wrote:
> >>> Quite some time ago Alexander Malmberg created a patch that gave
> >>> GNUstep font substitution capabilities. It has worked quite well.
> >>> Though, recent changes in GNUstep svn meant that the patch can no
> >>> longer be applied. I've manually applied his patch to svn (from a few
> >>> weeks ago), and created a new patch (attached). I was hoping this
> >>> could be commited to svn, so as to not become out of date again.
> >>>
> >>
> >> _______________________________________________
> >> Discuss-gnustep mailing list
> >> Discuss-gnustep@gnu.org
> >> http://lists.gnu.org/mailman/listinfo/discuss-gnustep
> >>
> >
>
>
- font substitution, foobix, 2007/08/05
- Re: font substitution, Fred Kiefer, 2007/08/05
- Re: font substitution, Yen-Ju Chen, 2007/08/05
- Re: font substitution, Fred Kiefer, 2007/08/07
- Re: font substitution,
Yen-Ju Chen <=
- Re: font substitution, Yen-Ju Chen, 2007/08/07
- Re: font substitution, Fred Kiefer, 2007/08/07
- Re: font substitution, Yen-Ju Chen, 2007/08/07
- Re: font substitution, Fred Kiefer, 2007/08/08
- Re: font substitution, Yen-Ju Chen, 2007/08/08
- Re: font substitution, Fred Kiefer, 2007/08/09
- Re: font substitution, Yen-Ju Chen, 2007/08/09
- Re: font substitution, Yen-Ju Chen, 2007/08/10
- Re: font substitution, Yen-Ju Chen, 2007/08/10
- Re: font substitution, Yen-Ju Chen, 2007/08/10