[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:13:58 -0700 |
On 8/7/07, Yen-Ju Chen <yjchenx@gmail.com> wrote:
> 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.
I forgot to ask, is there a user default to set the preferredFontNames ?
Otherwise, preferredFontNames will always return nil
unless applications explicitly set it in NSFont.
Yen-Ju
>
> 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, 2007/08/07
- Re: font substitution,
Yen-Ju Chen <=
- 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
- Re: font substitution, Fred Kiefer, 2007/08/11