vfs: check userland buffers before reading them.
[haiku.git] / src / servers / app / font / FontCacheEntry.cpp
blobfd2428d891f30154d04b36872af3d5b28907a328
1 /*
2 * Copyright 2007-2009, Haiku. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Maxim Shemanarev <mcseemagg@yahoo.com>
7 * Stephan Aßmus <superstippi@gmx.de>
8 * Andrej Spielmann, <andrej.spielmann@seh.ox.ac.uk>
9 */
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"
29 #include <string.h>
31 #include <new>
33 #include <Autolock.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
54 return key;
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;
72 public:
73 GlyphCachePool()
77 ~GlyphCachePool()
79 GlyphCache* glyph = fGlyphTable.Clear(true);
80 while (glyph != NULL) {
81 GlyphCache* next = glyph->hash_link;
82 delete glyph;
83 glyph = next;
87 status_t Init()
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);
103 if (glyph != NULL)
104 return NULL;
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) {
110 delete glyph;
111 return NULL;
114 // TODO: The HashTable grows without bounds. We should cleanup
115 // older entries from time to time.
117 fGlyphTable.Insert(glyph);
119 return glyph;
122 private:
123 typedef BOpenHashTable<GlyphHashTableDefinition> GlyphTable;
125 GlyphTable fGlyphTable;
129 // #pragma mark -
132 FontCacheEntry::FontCacheEntry()
134 MultiLocker("FontCacheEntry lock"),
135 fGlyphCache(new(std::nothrow) GlyphCachePool()),
136 fEngine(),
137 fLastUsedTime(LONGLONG_MIN),
138 fUseCounter(0)
143 FontCacheEntry::~FontCacheEntry()
145 //printf("~FontCacheEntry()\n");
146 delete fGlyphCache;
150 bool
151 FontCacheEntry::Init(const ServerFont& font, bool forceVector)
153 if (fGlyphCache == NULL)
154 return false;
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());
166 return false;
168 if (fGlyphCache->Init() != B_OK) {
169 fprintf(stderr, "FontCacheEntry::Init() - failed to allocate "
170 "GlyphCache table for font file %s\n", font.Path());
171 return false;
174 return true;
178 bool
179 FontCacheEntry::HasGlyphs(const char* utf8String, ssize_t length) const
181 uint32 glyphCode;
182 const char* start = utf8String;
183 while ((glyphCode = UTF8ToCharCode(&utf8String))) {
184 if (fGlyphCache->FindGlyph(glyphCode) == NULL)
185 return false;
186 if (utf8String - start + 1 > length)
187 break;
189 return true;
193 inline bool
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)
201 // another control
202 || (glyphCode == 0x00a0)
203 // no-break space
204 || (glyphCode == 0x1680)
205 // ogham space mark
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)
215 // medium math space
216 || (glyphCode == 0x3000)
217 // ideographic space
222 inline bool
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)
228 // soft hyphen
229 || (glyphCode == 0x034f)
230 // combining grapheme joiner
231 || (glyphCode >= 0x115f && glyphCode <= 0x1160)
232 // hangul fillers
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)
244 // hangul filler
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)
252 // reserved
253 || (glyphCode >= 0x1d173 && glyphCode <= 0x1d17a)
254 // musical symbols
255 || (glyphCode >= 0xe0000 && glyphCode <= 0xe01ef)
256 // variation selectors, tag space, reserved
261 const GlyphCache*
262 FontCacheEntry::CachedGlyph(uint32 glyphCode)
264 // Only requires a read lock.
265 return fGlyphCache->FindGlyph(glyphCode);
269 const GlyphCache*
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
279 // write-locked!
281 const GlyphCache* glyph = fGlyphCache->FindGlyph(glyphCode);
282 if (glyph != NULL)
283 return glyph;
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
302 engine = &fEngine;
303 if (render_as_space(glyphCode)) {
304 // get the normal space glyph
305 glyphIndex = engine->GlyphIndexForGlyphCode(0x20 /* space */);
306 } else {
307 // The glyph was not found anywhere.
308 return NULL;
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());
319 if (glyph != NULL)
320 engine->WriteGlyphTo(glyph->data);
323 return glyph;
327 void
328 FontCacheEntry::InitAdaptors(const GlyphCache* glyph,
329 double x, double y, GlyphMonoAdapter& monoAdapter,
330 GlyphGray8Adapter& gray8Adapter, GlyphPathAdapter& pathAdapter,
331 double scale)
333 if (glyph == NULL)
334 return;
336 switch(glyph->data_type) {
337 case glyph_data_mono:
338 monoAdapter.init(glyph->data, glyph->data_size, x, y);
339 break;
341 case glyph_data_gray8:
342 gray8Adapter.init(glyph->data, glyph->data_size, x, y);
343 break;
345 case glyph_data_subpix:
346 gray8Adapter.init(glyph->data, glyph->data_size, x, y);
347 break;
349 case glyph_data_outline:
350 pathAdapter.init(glyph->data, glyph->data_size, x, y, scale);
351 break;
353 default:
354 break;
359 bool
360 FontCacheEntry::GetKerning(uint32 glyphCode1, uint32 glyphCode2,
361 double* x, double* y)
363 return fEngine.GetKerning(glyphCode1, glyphCode2, x, y);
367 /*static*/ void
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);
384 void
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
389 // here at all
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();
395 fUseCounter++;
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
408 || font.Size() > 30
409 || !font.Hinting()) {
410 renderingType = glyph_ren_outline;
413 return renderingType;