xref: /haiku/src/servers/app/font/GlyphLayoutEngine.h (revision 7a8d5a2db3214be378c4450bd94e07db75d5e240)
1f4f30311SClemens Zeidler /*
291233f88SStephan Aßmus  * Copyright 2007-2014, Haiku. All rights reserved.
3f4f30311SClemens Zeidler  * Distributed under the terms of the MIT License.
4f4f30311SClemens Zeidler  *
5f4f30311SClemens Zeidler  * Authors:
6f4f30311SClemens Zeidler  *		Stephan Aßmus <superstippi@gmx.de>
7f4f30311SClemens Zeidler  */
8f4f30311SClemens Zeidler 
9f4f30311SClemens Zeidler #ifndef GLYPH_LAYOUT_ENGINE_H
10f4f30311SClemens Zeidler #define GLYPH_LAYOUT_ENGINE_H
11f4f30311SClemens Zeidler 
12f4f30311SClemens Zeidler #include "utf8_functions.h"
13f4f30311SClemens Zeidler 
14f4f30311SClemens Zeidler #include "FontCache.h"
15f4f30311SClemens Zeidler #include "FontCacheEntry.h"
16f4f30311SClemens Zeidler #include "FontManager.h"
17f4f30311SClemens Zeidler #include "ServerFont.h"
18f4f30311SClemens Zeidler 
19f4f30311SClemens Zeidler #include <Debug.h>
20f4f30311SClemens Zeidler 
21f4f30311SClemens Zeidler #include <ctype.h>
22f4f30311SClemens Zeidler 
23f4f30311SClemens Zeidler class FontCacheReference {
24f4f30311SClemens Zeidler public:
25f4f30311SClemens Zeidler 	FontCacheReference()
26f4f30311SClemens Zeidler 		:
27f4f30311SClemens Zeidler 		fCacheEntry(NULL),
28f4f30311SClemens Zeidler 		fWriteLocked(false)
29f4f30311SClemens Zeidler 	{
30f4f30311SClemens Zeidler 	}
31f4f30311SClemens Zeidler 
32f4f30311SClemens Zeidler 	~FontCacheReference()
33f4f30311SClemens Zeidler 	{
34f4f30311SClemens Zeidler 		Unset();
35f4f30311SClemens Zeidler 	}
36f4f30311SClemens Zeidler 
37f4f30311SClemens Zeidler 	void SetTo(FontCacheEntry* entry, bool writeLocked)
38f4f30311SClemens Zeidler 	{
39f4f30311SClemens Zeidler 		// NOTE: If the semantics are changed such
40f4f30311SClemens Zeidler 		// that the reference to a previous entry
41f4f30311SClemens Zeidler 		// is properly released, then don't forget
42f4f30311SClemens Zeidler 		// to adapt existing which transfers
43f4f30311SClemens Zeidler 		// responsibility of entries between
44f4f30311SClemens Zeidler 		// references!
45f4f30311SClemens Zeidler 		fCacheEntry = entry;
46f4f30311SClemens Zeidler 		fWriteLocked = writeLocked;
47f4f30311SClemens Zeidler 	}
48f4f30311SClemens Zeidler 
49f4f30311SClemens Zeidler 	void Unset()
50f4f30311SClemens Zeidler 	{
51f4f30311SClemens Zeidler 		if (fCacheEntry == NULL)
52f4f30311SClemens Zeidler 			return;
53f4f30311SClemens Zeidler 
54f4f30311SClemens Zeidler 		if (fWriteLocked)
55f4f30311SClemens Zeidler 			fCacheEntry->WriteUnlock();
56f4f30311SClemens Zeidler 		else
57f4f30311SClemens Zeidler 			fCacheEntry->ReadUnlock();
58f4f30311SClemens Zeidler 
59f4f30311SClemens Zeidler 		FontCache::Default()->Recycle(fCacheEntry);
60f4f30311SClemens Zeidler 	}
61f4f30311SClemens Zeidler 
62f4f30311SClemens Zeidler 	inline FontCacheEntry* Entry() const
63f4f30311SClemens Zeidler 	{
64f4f30311SClemens Zeidler 		return fCacheEntry;
65f4f30311SClemens Zeidler 	}
66f4f30311SClemens Zeidler 
67f4f30311SClemens Zeidler 	inline bool WriteLocked() const
68f4f30311SClemens Zeidler 	{
69f4f30311SClemens Zeidler 		return fWriteLocked;
70f4f30311SClemens Zeidler 	}
71f4f30311SClemens Zeidler 
72f4f30311SClemens Zeidler private:
73f4f30311SClemens Zeidler 			FontCacheEntry*		fCacheEntry;
74f4f30311SClemens Zeidler 			bool				fWriteLocked;
75f4f30311SClemens Zeidler };
76f4f30311SClemens Zeidler 
77f4f30311SClemens Zeidler 
78f4f30311SClemens Zeidler class GlyphLayoutEngine {
79f4f30311SClemens Zeidler public:
80f4f30311SClemens Zeidler 	static	bool				IsWhiteSpace(uint32 glyphCode);
81f4f30311SClemens Zeidler 
82f4f30311SClemens Zeidler 	static	FontCacheEntry*		FontCacheEntryFor(const ServerFont& font,
83750958b8SStephan Aßmus 									bool forceVector,
84f4f30311SClemens Zeidler 									const FontCacheEntry* disallowedEntry,
85f4f30311SClemens Zeidler 									const char* utf8String, int32 length,
86f4f30311SClemens Zeidler 									FontCacheReference& cacheReference,
87f4f30311SClemens Zeidler 									bool needsWriteLock);
88f4f30311SClemens Zeidler 
89f4f30311SClemens Zeidler 			template<class GlyphConsumer>
90f4f30311SClemens Zeidler 	static	bool				LayoutGlyphs(GlyphConsumer& consumer,
91f4f30311SClemens Zeidler 									const ServerFont& font,
92f4f30311SClemens Zeidler 									const char* utf8String,
938071db32SMichael Lotz 									int32 length, int32 maxChars,
94f4f30311SClemens Zeidler 									const escapement_delta* delta = NULL,
95f4f30311SClemens Zeidler 									uint8 spacing = B_BITMAP_SPACING,
96f4f30311SClemens Zeidler 									const BPoint* offsets = NULL,
97f4f30311SClemens Zeidler 									FontCacheReference* cacheReference = NULL);
98f4f30311SClemens Zeidler 
99f4f30311SClemens Zeidler private:
100f4f30311SClemens Zeidler 	static	bool				_WriteLockAndAcquireFallbackEntry(
101f4f30311SClemens Zeidler 									FontCacheReference& cacheReference,
102f4f30311SClemens Zeidler 									FontCacheEntry* entry,
103750958b8SStephan Aßmus 									const ServerFont& font, bool needsVector,
104f4f30311SClemens Zeidler 									const char* utf8String, int32 length,
105f4f30311SClemens Zeidler 									FontCacheReference& fallbackCacheReference,
106f4f30311SClemens Zeidler 									FontCacheEntry*& fallbackEntry);
107f4f30311SClemens Zeidler 
108f4f30311SClemens Zeidler 								GlyphLayoutEngine();
109f4f30311SClemens Zeidler 	virtual						~GlyphLayoutEngine();
110f4f30311SClemens Zeidler };
111f4f30311SClemens Zeidler 
112f4f30311SClemens Zeidler 
113f4f30311SClemens Zeidler inline bool
114f4f30311SClemens Zeidler GlyphLayoutEngine::IsWhiteSpace(uint32 charCode)
115f4f30311SClemens Zeidler {
116f4f30311SClemens Zeidler 	switch (charCode) {
117f4f30311SClemens Zeidler 		case 0x0009:	/* tab */
118f4f30311SClemens Zeidler 		case 0x000b:	/* vertical tab */
119f4f30311SClemens Zeidler 		case 0x000c:	/* form feed */
120f4f30311SClemens Zeidler 		case 0x0020:	/* space */
121f4f30311SClemens Zeidler 		case 0x00a0:	/* non breaking space */
122f4f30311SClemens Zeidler 		case 0x000a:	/* line feed */
123f4f30311SClemens Zeidler 		case 0x000d:	/* carriage return */
124f4f30311SClemens Zeidler 		case 0x2028:	/* line separator */
125f4f30311SClemens Zeidler 		case 0x2029:	/* paragraph separator */
126f4f30311SClemens Zeidler 			return true;
127f4f30311SClemens Zeidler 	}
128f4f30311SClemens Zeidler 
129f4f30311SClemens Zeidler 	return false;
130f4f30311SClemens Zeidler }
131f4f30311SClemens Zeidler 
132f4f30311SClemens Zeidler 
133f4f30311SClemens Zeidler inline FontCacheEntry*
134750958b8SStephan Aßmus GlyphLayoutEngine::FontCacheEntryFor(const ServerFont& font, bool forceVector,
135f4f30311SClemens Zeidler 	const FontCacheEntry* disallowedEntry, const char* utf8String, int32 length,
136f4f30311SClemens Zeidler 	FontCacheReference& cacheReference, bool needsWriteLock)
137f4f30311SClemens Zeidler {
138f4f30311SClemens Zeidler 	ASSERT(cacheReference.Entry() == NULL);
139f4f30311SClemens Zeidler 
140f4f30311SClemens Zeidler 	FontCache* cache = FontCache::Default();
141750958b8SStephan Aßmus 	FontCacheEntry* entry = cache->FontCacheEntryFor(font, forceVector);
142f4f30311SClemens Zeidler 	if (entry == NULL)
143f4f30311SClemens Zeidler 		return NULL;
144f4f30311SClemens Zeidler 
145f4f30311SClemens Zeidler 	if (entry == disallowedEntry) {
146f4f30311SClemens Zeidler 		cache->Recycle(entry);
147f4f30311SClemens Zeidler 		return NULL;
148f4f30311SClemens Zeidler 	}
149f4f30311SClemens Zeidler 
150f4f30311SClemens Zeidler 	if (needsWriteLock) {
151f4f30311SClemens Zeidler 		if (!entry->WriteLock()) {
152f4f30311SClemens Zeidler 			cache->Recycle(entry);
153f4f30311SClemens Zeidler 			return NULL;
154f4f30311SClemens Zeidler 		}
155f4f30311SClemens Zeidler 	} else {
156f4f30311SClemens Zeidler 		if (!entry->ReadLock()) {
157f4f30311SClemens Zeidler 			cache->Recycle(entry);
158f4f30311SClemens Zeidler 			return NULL;
159f4f30311SClemens Zeidler 		}
160f4f30311SClemens Zeidler 	}
161f4f30311SClemens Zeidler 
162f4f30311SClemens Zeidler 	// At this point, we have a valid FontCacheEntry and it is locked in the
163f4f30311SClemens Zeidler 	// proper mode. We can setup the FontCacheReference so it takes care of
164f4f30311SClemens Zeidler 	// the locking and recycling from now and return the entry.
165f4f30311SClemens Zeidler 	cacheReference.SetTo(entry, needsWriteLock);
166f4f30311SClemens Zeidler 	return entry;
167f4f30311SClemens Zeidler }
168f4f30311SClemens Zeidler 
169f4f30311SClemens Zeidler 
170f4f30311SClemens Zeidler template<class GlyphConsumer>
171f4f30311SClemens Zeidler inline bool
172f4f30311SClemens Zeidler GlyphLayoutEngine::LayoutGlyphs(GlyphConsumer& consumer,
173f4f30311SClemens Zeidler 	const ServerFont& font,
1748071db32SMichael Lotz 	const char* utf8String, int32 length, int32 maxChars,
17591233f88SStephan Aßmus 	const escapement_delta* delta, uint8 spacing,
176f4f30311SClemens Zeidler 	const BPoint* offsets, FontCacheReference* _cacheReference)
177f4f30311SClemens Zeidler {
178f4f30311SClemens Zeidler 	// TODO: implement spacing modes
179f4f30311SClemens Zeidler 	FontCacheEntry* entry = NULL;
180f4f30311SClemens Zeidler 	FontCacheReference cacheReference;
181f4f30311SClemens Zeidler 	FontCacheEntry* fallbackEntry = NULL;
182f4f30311SClemens Zeidler 	FontCacheReference fallbackCacheReference;
183f4f30311SClemens Zeidler 	if (_cacheReference != NULL) {
184f4f30311SClemens Zeidler 		entry = _cacheReference->Entry();
185f4f30311SClemens Zeidler 		// When there is already a cacheReference, it means there was already
186f4f30311SClemens Zeidler 		// an iteration over the glyphs. The use-case is for example to do
187f4f30311SClemens Zeidler 		// a layout pass to get the string width for the bounding box, then a
188f4f30311SClemens Zeidler 		// second layout pass to actually render the glyphs to the screen.
189f4f30311SClemens Zeidler 		// This means that the fallback entry mechanism will not do any good
190f4f30311SClemens Zeidler 		// for the second pass, since the fallback glyphs have been stored in
191f4f30311SClemens Zeidler 		// the original entry.
192f4f30311SClemens Zeidler 	}
193f4f30311SClemens Zeidler 
194f4f30311SClemens Zeidler 	if (entry == NULL) {
195750958b8SStephan Aßmus 		entry = FontCacheEntryFor(font, consumer.NeedsVector(), NULL,
196750958b8SStephan Aßmus 			utf8String, length, cacheReference, false);
197f4f30311SClemens Zeidler 
198f4f30311SClemens Zeidler 		if (entry == NULL)
199f4f30311SClemens Zeidler 			return false;
200f4f30311SClemens Zeidler 	} // else the entry was already used and is still locked
201f4f30311SClemens Zeidler 
202f4f30311SClemens Zeidler 	consumer.Start();
203f4f30311SClemens Zeidler 
204f4f30311SClemens Zeidler 	double x = 0.0;
205f4f30311SClemens Zeidler 	double y = 0.0;
206f4f30311SClemens Zeidler 	if (offsets) {
207f4f30311SClemens Zeidler 		x = offsets[0].x;
208f4f30311SClemens Zeidler 		y = offsets[0].y;
209f4f30311SClemens Zeidler 	}
210f4f30311SClemens Zeidler 
211f4f30311SClemens Zeidler 	double advanceX = 0.0;
212f4f30311SClemens Zeidler 	double advanceY = 0.0;
213b8f4968dSStephan Aßmus 	double size = font.Size();
214f4f30311SClemens Zeidler 
21591233f88SStephan Aßmus 	uint32 lastCharCode = 0; // Needed for kerning in B_STRING_SPACING mode
216f4f30311SClemens Zeidler 	uint32 charCode;
217f4f30311SClemens Zeidler 	int32 index = 0;
218f4f30311SClemens Zeidler 	bool writeLocked = false;
219f4f30311SClemens Zeidler 	const char* start = utf8String;
2208071db32SMichael Lotz 	while (maxChars-- > 0 && (charCode = UTF8ToCharCode(&utf8String)) != 0) {
221f4f30311SClemens Zeidler 
22224c156daSStephan Aßmus 		if (offsets != NULL) {
223f4f30311SClemens Zeidler 			// Use direct glyph locations instead of calculating them
224f4f30311SClemens Zeidler 			// from the advance values
225f4f30311SClemens Zeidler 			x = offsets[index].x;
226f4f30311SClemens Zeidler 			y = offsets[index].y;
227f4f30311SClemens Zeidler 		} else {
22891233f88SStephan Aßmus 			if (spacing == B_STRING_SPACING)
22991233f88SStephan Aßmus 				entry->GetKerning(lastCharCode, charCode, &advanceX, &advanceY);
230f4f30311SClemens Zeidler 
231f4f30311SClemens Zeidler 			x += advanceX;
232f4f30311SClemens Zeidler 			y += advanceY;
233f4f30311SClemens Zeidler 		}
234f4f30311SClemens Zeidler 
235f4f30311SClemens Zeidler 		const GlyphCache* glyph = entry->CachedGlyph(charCode);
236f4f30311SClemens Zeidler 		if (glyph == NULL) {
237f4f30311SClemens Zeidler 			// The glyph has not been cached yet, switch to a write lock,
238f4f30311SClemens Zeidler 			// acquire the fallback entry and create the glyph. Note that
239f4f30311SClemens Zeidler 			// the write lock will persist (in the cacheReference) so that
240f4f30311SClemens Zeidler 			// we only have to do this switch once for the whole string.
241f4f30311SClemens Zeidler 			if (!writeLocked) {
242f4f30311SClemens Zeidler 				writeLocked = _WriteLockAndAcquireFallbackEntry(cacheReference,
243750958b8SStephan Aßmus 					entry, font, consumer.NeedsVector(), utf8String, length,
244750958b8SStephan Aßmus 					fallbackCacheReference, fallbackEntry);
245f4f30311SClemens Zeidler 			}
246f4f30311SClemens Zeidler 
247f4f30311SClemens Zeidler 			if (writeLocked)
248f4f30311SClemens Zeidler 				glyph = entry->CreateGlyph(charCode, fallbackEntry);
249f4f30311SClemens Zeidler 		}
250f4f30311SClemens Zeidler 
251f4f30311SClemens Zeidler 		if (glyph == NULL) {
252f4f30311SClemens Zeidler 			consumer.ConsumeEmptyGlyph(index++, charCode, x, y);
253f4f30311SClemens Zeidler 			advanceX = 0;
254f4f30311SClemens Zeidler 			advanceY = 0;
255f4f30311SClemens Zeidler 		} else {
256f4f30311SClemens Zeidler 			// get next increment for pen position
257d9d14326SStephan Aßmus 			if (spacing == B_CHAR_SPACING) {
258b8f4968dSStephan Aßmus 				advanceX = glyph->precise_advance_x * size;
259b8f4968dSStephan Aßmus 				advanceY = glyph->precise_advance_y * size;
260d9d14326SStephan Aßmus 			} else {
261f4f30311SClemens Zeidler 				advanceX = glyph->advance_x;
262f4f30311SClemens Zeidler 				advanceY = glyph->advance_y;
263d9d14326SStephan Aßmus 			}
2644ccc40a1SStephan Aßmus 
2654ccc40a1SStephan Aßmus 			// adjust for custom spacing
2664ccc40a1SStephan Aßmus 			if (delta != NULL) {
2674ccc40a1SStephan Aßmus 				advanceX += IsWhiteSpace(charCode)
2684ccc40a1SStephan Aßmus 					? delta->space : delta->nonspace;
2694ccc40a1SStephan Aßmus 			}
2704ccc40a1SStephan Aßmus 
2714ccc40a1SStephan Aßmus 			if (!consumer.ConsumeGlyph(index++, charCode, glyph, entry, x, y,
2724ccc40a1SStephan Aßmus 					advanceX, advanceY)) {
2734ccc40a1SStephan Aßmus 				advanceX = 0.0;
2744ccc40a1SStephan Aßmus 				advanceY = 0.0;
2754ccc40a1SStephan Aßmus 				break;
2764ccc40a1SStephan Aßmus 			}
277f4f30311SClemens Zeidler 		}
278f4f30311SClemens Zeidler 
27991233f88SStephan Aßmus 		lastCharCode = charCode;
280f4f30311SClemens Zeidler 		if (utf8String - start + 1 > length)
281f4f30311SClemens Zeidler 			break;
282f4f30311SClemens Zeidler 	}
283f4f30311SClemens Zeidler 
284f4f30311SClemens Zeidler 	x += advanceX;
285f4f30311SClemens Zeidler 	y += advanceY;
286f4f30311SClemens Zeidler 	consumer.Finish(x, y);
287f4f30311SClemens Zeidler 
288f4f30311SClemens Zeidler 	if (_cacheReference != NULL && _cacheReference->Entry() == NULL) {
289f4f30311SClemens Zeidler 		// The caller passed a FontCacheReference, but this is the first
290f4f30311SClemens Zeidler 		// iteration -> switch the ownership from the stack allocated
291f4f30311SClemens Zeidler 		// FontCacheReference to the one passed by the caller. The fallback
292f4f30311SClemens Zeidler 		// FontCacheReference is not affected by this, since it is never used
293f4f30311SClemens Zeidler 		// during a second iteration.
294f4f30311SClemens Zeidler 		_cacheReference->SetTo(entry, cacheReference.WriteLocked());
295f4f30311SClemens Zeidler 		cacheReference.SetTo(NULL, false);
296f4f30311SClemens Zeidler 	}
297f4f30311SClemens Zeidler 	return true;
298f4f30311SClemens Zeidler }
299f4f30311SClemens Zeidler 
300f4f30311SClemens Zeidler 
301f4f30311SClemens Zeidler inline bool
302f4f30311SClemens Zeidler GlyphLayoutEngine::_WriteLockAndAcquireFallbackEntry(
303f4f30311SClemens Zeidler 	FontCacheReference& cacheReference, FontCacheEntry* entry,
304750958b8SStephan Aßmus 	const ServerFont& font, bool forceVector, const char* utf8String,
305750958b8SStephan Aßmus 	int32 length, FontCacheReference& fallbackCacheReference,
306750958b8SStephan Aßmus 	FontCacheEntry*& fallbackEntry)
307f4f30311SClemens Zeidler {
30834fbc56bSAdrien Destugues 	// We need a fallback font, since potentially, we have to obtain missing
309f4f30311SClemens Zeidler 	// glyphs from it. We need to obtain the fallback font while we have not
310f4f30311SClemens Zeidler 	// locked anything, since locking the FontManager with the write-lock held
311f4f30311SClemens Zeidler 	// can obvisouly lead to a deadlock.
312f4f30311SClemens Zeidler 
31315325401SAdrien Destugues 	bool writeLocked = entry->IsWriteLocked();
31415325401SAdrien Destugues 
31515325401SAdrien Destugues 	if (writeLocked) {
31615325401SAdrien Destugues 		entry->WriteUnlock();
31715325401SAdrien Destugues 	} else {
318f4f30311SClemens Zeidler 		cacheReference.SetTo(NULL, false);
319f4f30311SClemens Zeidler 		entry->ReadUnlock();
32015325401SAdrien Destugues 	}
321f4f30311SClemens Zeidler 
32234fbc56bSAdrien Destugues 	// TODO: We always get the fallback glyphs from the Noto family, but of
32334fbc56bSAdrien Destugues 	// course the fallback font should a) contain the missing glyphs at all
32434fbc56bSAdrien Destugues 	// and b) be similar to the original font. So there should be a mapping
32534fbc56bSAdrien Destugues 	// of some kind to know the most suitable fallback font.
32634fbc56bSAdrien Destugues 	static const char* fallbacks[] = {
327177db1e4SAugustin Cavalier 		"Noto Sans Display",
32834fbc56bSAdrien Destugues 		"Noto Sans CJK JP",
329a652a5feSBrian Hill 		"Noto Sans Symbols",
33034fbc56bSAdrien Destugues 		NULL
33134fbc56bSAdrien Destugues 	};
33234fbc56bSAdrien Destugues 
33334fbc56bSAdrien Destugues 	int i = 0;
33434fbc56bSAdrien Destugues 
33534fbc56bSAdrien Destugues 	// Try to get the glyph from the fallback fonts
336cd6365c7SJérôme Duval 	while (fallbacks[i] != NULL) {
337f4f30311SClemens Zeidler 		if (gFontManager->Lock()) {
338*7a8d5a2dSPascal Abresch 			FontStyle* fallbackStyle = gFontManager->GetStyle(
339*7a8d5a2dSPascal Abresch 				fallbacks[i], font.Style());
340*7a8d5a2dSPascal Abresch 
341f4f30311SClemens Zeidler 			if (fallbackStyle != NULL) {
342f4f30311SClemens Zeidler 				ServerFont fallbackFont(*fallbackStyle, font.Size());
343f4f30311SClemens Zeidler 				gFontManager->Unlock();
34434fbc56bSAdrien Destugues 
345f4f30311SClemens Zeidler 				// Force the write-lock on the fallback entry, since we
346f4f30311SClemens Zeidler 				// don't transfer or copy GlyphCache objects from one cache
347f4f30311SClemens Zeidler 				// to the other, but create new glyphs which are stored in
348f4f30311SClemens Zeidler 				// "entry" in any case, which requires the write cache for
349f4f30311SClemens Zeidler 				// sure (used FontEngine of fallbackEntry).
35034fbc56bSAdrien Destugues 				fallbackEntry = FontCacheEntryFor(fallbackFont, forceVector,
35134fbc56bSAdrien Destugues 					entry, utf8String, length, fallbackCacheReference, true);
35234fbc56bSAdrien Destugues 
35334fbc56bSAdrien Destugues 				if (fallbackEntry != NULL)
35434fbc56bSAdrien Destugues 					break;
355f4f30311SClemens Zeidler 			} else
356f4f30311SClemens Zeidler 				gFontManager->Unlock();
357f4f30311SClemens Zeidler 		}
358f4f30311SClemens Zeidler 
35934fbc56bSAdrien Destugues 		i++;
36034fbc56bSAdrien Destugues 	}
36134fbc56bSAdrien Destugues 	// NOTE: We don't care if fallbackEntry is still NULL, fetching
36234fbc56bSAdrien Destugues 	// alternate glyphs will simply not work.
36334fbc56bSAdrien Destugues 
364f4f30311SClemens Zeidler 	if (!entry->WriteLock()) {
365f4f30311SClemens Zeidler 		FontCache::Default()->Recycle(entry);
366f4f30311SClemens Zeidler 		return false;
367f4f30311SClemens Zeidler 	}
368f4f30311SClemens Zeidler 
36915325401SAdrien Destugues 	if (!writeLocked) {
370f4f30311SClemens Zeidler 		// Update the FontCacheReference, since the locking kind changed.
371f4f30311SClemens Zeidler 		cacheReference.SetTo(entry, true);
37215325401SAdrien Destugues 	}
373f4f30311SClemens Zeidler 	return true;
374f4f30311SClemens Zeidler }
375f4f30311SClemens Zeidler 
376f4f30311SClemens Zeidler 
377f4f30311SClemens Zeidler #endif // GLYPH_LAYOUT_ENGINE_H
378