2 * Copyright 2007-2009, Haiku. All rights reserved.
3 * Distributed under the terms of the MIT License.
6 * Maxim Shemanarev <mcseemagg@yahoo.com>
7 * Stephan Aßmus <superstippi@gmx.de>
8 * Andrej Spielmann, <andrej.spielmann@seh.ox.ac.uk>
11 //----------------------------------------------------------------------------
12 // Anti-Grain Geometry - Version 2.4
13 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
15 // Permission to copy, use, modify, sell and distribute this software
16 // is granted provided this copyright notice appears in all copies.
17 // This software is provided "as is" without express or implied
18 // warranty, and with no claim as to its suitability for any purpose.
20 //----------------------------------------------------------------------------
21 // Contact: mcseem@antigrain.com
22 // mcseemagg@yahoo.com
23 // http://www.antigrain.com
24 //----------------------------------------------------------------------------
27 #include "FontCacheEntry.h"
35 #include <agg_array.h>
36 #include <utf8_functions.h>
37 #include <util/OpenHashTable.h>
39 #include "GlobalSubpixelSettings.h"
42 BLocker
FontCacheEntry::sUsageUpdateLock("FontCacheEntry usage lock");
45 class FontCacheEntry::GlyphCachePool
{
46 // This class needs to be defined before any inline functions, as otherwise
47 // gcc2 will barf in debug mode.
48 struct GlyphHashTableDefinition
{
49 typedef uint32 KeyType
;
50 typedef GlyphCache ValueType
;
52 size_t HashKey(uint32 key
) const
57 size_t Hash(GlyphCache
* value
) const
59 return value
->glyph_index
;
62 bool Compare(uint32 key
, GlyphCache
* value
) const
64 return value
->glyph_index
== key
;
67 GlyphCache
*& GetLink(GlyphCache
* value
) const
69 return value
->hash_link
;
79 GlyphCache
* glyph
= fGlyphTable
.Clear(true);
80 while (glyph
!= NULL
) {
81 GlyphCache
* next
= glyph
->hash_link
;
89 return fGlyphTable
.Init();
92 const GlyphCache
* FindGlyph(uint32 glyphIndex
) const
94 return fGlyphTable
.Lookup(glyphIndex
);
97 GlyphCache
* CacheGlyph(uint32 glyphIndex
,
98 uint32 dataSize
, glyph_data_type dataType
, const agg::rect_i
& bounds
,
99 float advanceX
, float advanceY
, float preciseAdvanceX
,
100 float preciseAdvanceY
, float insetLeft
, float insetRight
)
102 GlyphCache
* glyph
= fGlyphTable
.Lookup(glyphIndex
);
106 glyph
= new(std::nothrow
) GlyphCache(glyphIndex
, dataSize
, dataType
,
107 bounds
, advanceX
, advanceY
, preciseAdvanceX
, preciseAdvanceY
,
108 insetLeft
, insetRight
);
109 if (glyph
== NULL
|| glyph
->data
== NULL
) {
114 // TODO: The HashTable grows without bounds. We should cleanup
115 // older entries from time to time.
117 fGlyphTable
.Insert(glyph
);
123 typedef BOpenHashTable
<GlyphHashTableDefinition
> GlyphTable
;
125 GlyphTable fGlyphTable
;
132 FontCacheEntry::FontCacheEntry()
134 MultiLocker("FontCacheEntry lock"),
135 fGlyphCache(new(std::nothrow
) GlyphCachePool()),
137 fLastUsedTime(LONGLONG_MIN
),
143 FontCacheEntry::~FontCacheEntry()
145 //printf("~FontCacheEntry()\n");
151 FontCacheEntry::Init(const ServerFont
& font
, bool forceVector
)
153 if (fGlyphCache
== NULL
)
156 glyph_rendering renderingType
= _RenderTypeFor(font
, forceVector
);
158 // TODO: encoding from font
159 FT_Encoding charMap
= FT_ENCODING_NONE
;
160 bool hinting
= font
.Hinting();
162 if (!fEngine
.Init(font
.Path(), 0, font
.Size(), charMap
,
163 renderingType
, hinting
)) {
164 fprintf(stderr
, "FontCacheEntry::Init() - some error loading font "
165 "file %s\n", font
.Path());
168 if (fGlyphCache
->Init() != B_OK
) {
169 fprintf(stderr
, "FontCacheEntry::Init() - failed to allocate "
170 "GlyphCache table for font file %s\n", font
.Path());
179 FontCacheEntry::HasGlyphs(const char* utf8String
, ssize_t length
) const
182 const char* start
= utf8String
;
183 while ((glyphCode
= UTF8ToCharCode(&utf8String
))) {
184 if (fGlyphCache
->FindGlyph(glyphCode
) == NULL
)
186 if (utf8String
- start
+ 1 > length
)
194 render_as_space(uint32 glyphCode
)
196 // whitespace: render as space
197 // as per Unicode PropList.txt: White_Space
198 return (glyphCode
>= 0x0009 && glyphCode
<= 0x000d)
199 // control characters
200 || (glyphCode
== 0x0085)
202 || (glyphCode
== 0x00a0)
204 || (glyphCode
== 0x1680)
206 || (glyphCode
== 0x180e)
207 // mongolian vowel separator
208 || (glyphCode
>= 0x2000 && glyphCode
<= 0x200a)
209 // en quand, hair space
210 || (glyphCode
>= 0x2028 && glyphCode
<= 0x2029)
211 // line and paragraph separators
212 || (glyphCode
== 0x202f)
213 // narrow no-break space
214 || (glyphCode
== 0x205f)
216 || (glyphCode
== 0x3000)
223 render_as_zero_width(uint32 glyphCode
)
225 // ignorable chars: render as invisible
226 // as per Unicode DerivedCoreProperties.txt: Default_Ignorable_Code_Point
227 return (glyphCode
== 0x00ad)
229 || (glyphCode
== 0x034f)
230 // combining grapheme joiner
231 || (glyphCode
>= 0x115f && glyphCode
<= 0x1160)
233 || (glyphCode
>= 0x17b4 && glyphCode
<= 0x17b5)
234 // ignorable khmer vowels
235 || (glyphCode
>= 0x180b && glyphCode
<= 0x180d)
236 // variation selectors
237 || (glyphCode
>= 0x200b && glyphCode
<= 0x200f)
238 // zero width space, cursive joiners, ltr marks
239 || (glyphCode
>= 0x202a && glyphCode
<= 0x202e)
240 // left to right embed, override
241 || (glyphCode
>= 0x2060 && glyphCode
<= 0x206f)
242 // word joiner, invisible math operators, reserved
243 || (glyphCode
== 0x3164)
245 || (glyphCode
>= 0xfe00 && glyphCode
<= 0xfe0f)
246 // variation selectors
247 || (glyphCode
== 0xfeff)
248 // zero width no-break space
249 || (glyphCode
== 0xffa0)
250 // halfwidth hangul filler
251 || (glyphCode
>= 0xfff0 && glyphCode
<= 0xfff8)
253 || (glyphCode
>= 0x1d173 && glyphCode
<= 0x1d17a)
255 || (glyphCode
>= 0xe0000 && glyphCode
<= 0xe01ef)
256 // variation selectors, tag space, reserved
262 FontCacheEntry::CachedGlyph(uint32 glyphCode
)
264 // Only requires a read lock.
265 return fGlyphCache
->FindGlyph(glyphCode
);
270 FontCacheEntry::CreateGlyph(uint32 glyphCode
, FontCacheEntry
* fallbackEntry
)
272 // We cache the glyph by the requested glyphCode. The FontEngine of this
273 // FontCacheEntry may not contain a glyph for the given code, in which case
274 // we ask the fallbackEntry for the code to index translation and let it
275 // generate the glyph data. We will still use our own cache for storing the
276 // glyph. The next time it will be found (by glyphCode).
278 // NOTE: Both this and the fallback FontCacheEntry are expected to be
281 const GlyphCache
* glyph
= fGlyphCache
->FindGlyph(glyphCode
);
285 FontEngine
* engine
= &fEngine
;
286 uint32 glyphIndex
= engine
->GlyphIndexForGlyphCode(glyphCode
);
287 if (glyphIndex
== 0 && fallbackEntry
!= NULL
) {
288 // Our FontEngine does not contain this glyph, but we can retry with
289 // the fallbackEntry.
290 engine
= &fallbackEntry
->fEngine
;
291 glyphIndex
= engine
->GlyphIndexForGlyphCode(glyphCode
);
294 if (glyphIndex
== 0) {
295 if (render_as_zero_width(glyphCode
)) {
296 // cache and return a zero width glyph
297 return fGlyphCache
->CacheGlyph(glyphCode
, 0, glyph_data_invalid
,
298 agg::rect_i(0, 0, -1, -1), 0, 0, 0, 0, 0, 0);
301 // reset to our engine
303 if (render_as_space(glyphCode
)) {
304 // get the normal space glyph
305 glyphIndex
= engine
->GlyphIndexForGlyphCode(0x20 /* space */);
307 // The glyph was not found anywhere.
312 if (engine
->PrepareGlyph(glyphIndex
)) {
313 glyph
= fGlyphCache
->CacheGlyph(glyphCode
,
314 engine
->DataSize(), engine
->DataType(), engine
->Bounds(),
315 engine
->AdvanceX(), engine
->AdvanceY(),
316 engine
->PreciseAdvanceX(), engine
->PreciseAdvanceY(),
317 engine
->InsetLeft(), engine
->InsetRight());
320 engine
->WriteGlyphTo(glyph
->data
);
328 FontCacheEntry::InitAdaptors(const GlyphCache
* glyph
,
329 double x
, double y
, GlyphMonoAdapter
& monoAdapter
,
330 GlyphGray8Adapter
& gray8Adapter
, GlyphPathAdapter
& pathAdapter
,
336 switch(glyph
->data_type
) {
337 case glyph_data_mono
:
338 monoAdapter
.init(glyph
->data
, glyph
->data_size
, x
, y
);
341 case glyph_data_gray8
:
342 gray8Adapter
.init(glyph
->data
, glyph
->data_size
, x
, y
);
345 case glyph_data_subpix
:
346 gray8Adapter
.init(glyph
->data
, glyph
->data_size
, x
, y
);
349 case glyph_data_outline
:
350 pathAdapter
.init(glyph
->data
, glyph
->data_size
, x
, y
, scale
);
360 FontCacheEntry::GetKerning(uint32 glyphCode1
, uint32 glyphCode2
,
361 double* x
, double* y
)
363 return fEngine
.GetKerning(glyphCode1
, glyphCode2
, x
, y
);
368 FontCacheEntry::GenerateSignature(char* signature
, size_t signatureSize
,
369 const ServerFont
& font
, bool forceVector
)
371 glyph_rendering renderingType
= _RenderTypeFor(font
, forceVector
);
373 // TODO: read more of these from the font
374 FT_Encoding charMap
= FT_ENCODING_NONE
;
375 bool hinting
= font
.Hinting();
376 uint8 averageWeight
= gSubpixelAverageWeight
;
378 snprintf(signature
, signatureSize
, "%" B_PRId32
",%u,%d,%d,%.1f,%d,%d",
379 font
.GetFamilyAndStyle(), charMap
,
380 font
.Face(), int(renderingType
), font
.Size(), hinting
, averageWeight
);
385 FontCacheEntry::UpdateUsage()
387 // this is a static lock to prevent usage of too many semaphores,
388 // but on the other hand, it is not so nice to be using a lock
390 // the hope is that the time is so short to hold this lock, that
391 // there is not much contention
392 BAutolock
_(sUsageUpdateLock
);
394 fLastUsedTime
= system_time();
399 /*static*/ glyph_rendering
400 FontCacheEntry::_RenderTypeFor(const ServerFont
& font
, bool forceVector
)
402 glyph_rendering renderingType
= gSubpixelAntialiasing
?
403 glyph_ren_subpix
: glyph_ren_native_gray8
;
405 if (forceVector
|| font
.Rotation() != 0.0 || font
.Shear() != 90.0
406 || font
.FalseBoldWidth() != 0.0
407 || (font
.Flags() & B_DISABLE_ANTIALIASING
) != 0
409 || !font
.Hinting()) {
410 renderingType
= glyph_ren_outline
;
413 return renderingType
;