PageRenderTime 83ms CodeModel.GetById 10ms app.highlight 68ms RepoModel.GetById 2ms app.codeStats 0ms

/indra/llrender/llfontfreetype.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 595 lines | 439 code | 97 blank | 59 comment | 65 complexity | 2de0f25948265440b840ceecacde2223 MD5 | raw file
  1/** 
  2 * @file llfontfreetype.cpp
  3 * @brief Freetype font library wrapper
  4 *
  5 * $LicenseInfo:firstyear=2002&license=viewerlgpl$
  6 * Second Life Viewer Source Code
  7 * Copyright (C) 2010, Linden Research, Inc.
  8 * 
  9 * This library is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU Lesser General Public
 11 * License as published by the Free Software Foundation;
 12 * version 2.1 of the License only.
 13 * 
 14 * This library is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * Lesser General Public License for more details.
 18 * 
 19 * You should have received a copy of the GNU Lesser General Public
 20 * License along with this library; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 22 * 
 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 24 * $/LicenseInfo$
 25 */
 26
 27#include "linden_common.h"
 28
 29#include "llfontfreetype.h"
 30#include "llfontgl.h"
 31
 32// Freetype stuff
 33#include <ft2build.h>
 34
 35// For some reason, this won't work if it's not wrapped in the ifdef
 36#ifdef FT_FREETYPE_H
 37#include FT_FREETYPE_H
 38#endif
 39
 40#include "llerror.h"
 41#include "llimage.h"
 42//#include "llimagej2c.h"
 43#include "llmath.h"	// Linden math
 44#include "llstring.h"
 45//#include "imdebug.h"
 46#include "llfontbitmapcache.h"
 47#include "llgl.h"
 48
 49FT_Render_Mode gFontRenderMode = FT_RENDER_MODE_NORMAL;
 50
 51LLFontManager *gFontManagerp = NULL;
 52
 53FT_Library gFTLibrary = NULL;
 54
 55//static
 56void LLFontManager::initClass()
 57{
 58	if (!gFontManagerp) 
 59	{
 60		gFontManagerp = new LLFontManager;
 61	}
 62}
 63
 64//static
 65void LLFontManager::cleanupClass()
 66{
 67	delete gFontManagerp;
 68	gFontManagerp = NULL;
 69}
 70
 71LLFontManager::LLFontManager()
 72{
 73	int error;
 74	error = FT_Init_FreeType(&gFTLibrary);
 75	if (error)
 76	{
 77		// Clean up freetype libs.
 78		llerrs << "Freetype initialization failure!" << llendl;
 79		FT_Done_FreeType(gFTLibrary);
 80	}
 81}
 82
 83LLFontManager::~LLFontManager()
 84{
 85	FT_Done_FreeType(gFTLibrary);
 86}
 87
 88
 89LLFontGlyphInfo::LLFontGlyphInfo(U32 index)
 90:	mGlyphIndex(index),
 91	mWidth(0),			// In pixels
 92	mHeight(0),			// In pixels
 93	mXAdvance(0.f),		// In pixels
 94	mYAdvance(0.f),		// In pixels
 95	mXBitmapOffset(0), 	// Offset to the origin in the bitmap
 96	mYBitmapOffset(0), 	// Offset to the origin in the bitmap
 97	mXBearing(0),		// Distance from baseline to left in pixels
 98	mYBearing(0),		// Distance from baseline to top in pixels
 99	mBitmapNum(0) // Which bitmap in the bitmap cache contains this glyph
100{
101}
102
103LLFontFreetype::LLFontFreetype()
104:	mFontBitmapCachep(new LLFontBitmapCache),
105	mValid(FALSE),
106	mAscender(0.f),
107	mDescender(0.f),
108	mLineHeight(0.f),
109	mIsFallback(FALSE),
110	mFTFace(NULL),
111	mRenderGlyphCount(0),
112	mAddGlyphCount(0),
113	mStyle(0),
114	mPointSize(0)
115{
116}
117
118
119LLFontFreetype::~LLFontFreetype()
120{
121	// Clean up freetype libs.
122	if (mFTFace)
123		FT_Done_Face(mFTFace);
124	mFTFace = NULL;
125
126	// Delete glyph info
127	std::for_each(mCharGlyphInfoMap.begin(), mCharGlyphInfoMap.end(), DeletePairedPointer());
128
129	// mFontBitmapCachep will be cleaned up by LLPointer destructor.
130	// mFallbackFonts cleaned up by LLPointer destructor
131}
132
133BOOL LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, S32 components, BOOL is_fallback)
134{
135	// Don't leak face objects.  This is also needed to deal with
136	// changed font file names.
137	if (mFTFace)
138	{
139		FT_Done_Face(mFTFace);
140		mFTFace = NULL;
141	}
142	
143	int error;
144
145	error = FT_New_Face( gFTLibrary,
146						 filename.c_str(),
147						 0,
148						 &mFTFace );
149
150    if (error)
151	{
152		return FALSE;
153	}
154
155	mIsFallback = is_fallback;
156	F32 pixels_per_em = (point_size / 72.f)*vert_dpi; // Size in inches * dpi
157
158	error = FT_Set_Char_Size(mFTFace,    /* handle to face object           */
159							0,       /* char_width in 1/64th of points  */
160							(S32)(point_size*64),   /* char_height in 1/64th of points */
161							(U32)horz_dpi,     /* horizontal device resolution    */
162							(U32)vert_dpi);   /* vertical device resolution      */
163
164	if (error)
165	{
166		// Clean up freetype libs.
167		FT_Done_Face(mFTFace);
168		mFTFace = NULL;
169		return FALSE;
170	}
171
172	F32 y_max, y_min, x_max, x_min;
173	F32 ems_per_unit = 1.f/ mFTFace->units_per_EM;
174	F32 pixels_per_unit = pixels_per_em * ems_per_unit;
175
176	// Get size of bbox in pixels
177	y_max = mFTFace->bbox.yMax * pixels_per_unit;
178	y_min = mFTFace->bbox.yMin * pixels_per_unit;
179	x_max = mFTFace->bbox.xMax * pixels_per_unit;
180	x_min = mFTFace->bbox.xMin * pixels_per_unit;
181	mAscender = mFTFace->ascender * pixels_per_unit;
182	mDescender = -mFTFace->descender * pixels_per_unit;
183	mLineHeight = mFTFace->height * pixels_per_unit;
184
185	S32 max_char_width = llround(0.5f + (x_max - x_min));
186	S32 max_char_height = llround(0.5f + (y_max - y_min));
187
188	mFontBitmapCachep->init(components, max_char_width, max_char_height);
189
190	if (!mFTFace->charmap)
191	{
192		//llinfos << " no unicode encoding, set whatever encoding there is..." << llendl;
193		FT_Set_Charmap(mFTFace, mFTFace->charmaps[0]);
194	}
195
196	if (!mIsFallback)
197	{
198		// Add the default glyph
199		addGlyphFromFont(this, 0, 0);
200	}
201
202	mName = filename;
203	mPointSize = point_size;
204
205	mStyle = LLFontGL::NORMAL;
206	if(mFTFace->style_flags & FT_STYLE_FLAG_BOLD)
207	{
208		mStyle |= LLFontGL::BOLD;
209		mStyle &= ~LLFontGL::NORMAL;
210	}
211
212	if(mFTFace->style_flags & FT_STYLE_FLAG_ITALIC)
213	{
214		mStyle |= LLFontGL::ITALIC;
215		mStyle &= ~LLFontGL::NORMAL;
216	}
217
218	return TRUE;
219}
220
221void LLFontFreetype::setFallbackFonts(const font_vector_t &font)
222{
223	mFallbackFonts = font;
224}
225
226const LLFontFreetype::font_vector_t &LLFontFreetype::getFallbackFonts() const
227{
228	return mFallbackFonts;
229}
230
231F32 LLFontFreetype::getLineHeight() const
232{
233	return mLineHeight;
234}
235
236F32 LLFontFreetype::getAscenderHeight() const
237{
238	return mAscender;
239}
240
241F32 LLFontFreetype::getDescenderHeight() const
242{
243	return mDescender;
244}
245
246F32 LLFontFreetype::getXAdvance(llwchar wch) const
247{
248	if (mFTFace == NULL)
249		return 0.0;
250
251	// Return existing info only if it is current
252	LLFontGlyphInfo* gi = getGlyphInfo(wch);
253	if (gi)
254	{
255		return gi->mXAdvance;
256	}
257	else
258	{
259		char_glyph_info_map_t::iterator found_it = mCharGlyphInfoMap.find((llwchar)0);
260		if (found_it != mCharGlyphInfoMap.end())
261		{
262			return found_it->second->mXAdvance;
263		}
264	}
265
266	// Last ditch fallback - no glyphs defined at all.
267	return (F32)mFontBitmapCachep->getMaxCharWidth();
268}
269
270F32 LLFontFreetype::getXAdvance(const LLFontGlyphInfo* glyph) const
271{
272	if (mFTFace == NULL)
273		return 0.0;
274
275	return glyph->mXAdvance;
276}
277
278F32 LLFontFreetype::getXKerning(llwchar char_left, llwchar char_right) const
279{
280	if (mFTFace == NULL)
281		return 0.0;
282
283	//llassert(!mIsFallback);
284	LLFontGlyphInfo* left_glyph_info = getGlyphInfo(char_left);;
285	U32 left_glyph = left_glyph_info ? left_glyph_info->mGlyphIndex : 0;
286	// Kern this puppy.
287	LLFontGlyphInfo* right_glyph_info = getGlyphInfo(char_right);
288	U32 right_glyph = right_glyph_info ? right_glyph_info->mGlyphIndex : 0;
289
290	FT_Vector  delta;
291
292	llverify(!FT_Get_Kerning(mFTFace, left_glyph, right_glyph, ft_kerning_unfitted, &delta));
293
294	return delta.x*(1.f/64.f);
295}
296
297F32 LLFontFreetype::getXKerning(const LLFontGlyphInfo* left_glyph_info, const LLFontGlyphInfo* right_glyph_info) const
298{
299	if (mFTFace == NULL)
300		return 0.0;
301
302	U32 left_glyph = left_glyph_info ? left_glyph_info->mGlyphIndex : 0;
303	U32 right_glyph = right_glyph_info ? right_glyph_info->mGlyphIndex : 0;
304
305	FT_Vector  delta;
306
307	llverify(!FT_Get_Kerning(mFTFace, left_glyph, right_glyph, ft_kerning_unfitted, &delta));
308
309	return delta.x*(1.f/64.f);
310}
311
312BOOL LLFontFreetype::hasGlyph(llwchar wch) const
313{
314	llassert(!mIsFallback);
315	return(mCharGlyphInfoMap.find(wch) != mCharGlyphInfoMap.end());
316}
317
318LLFontGlyphInfo* LLFontFreetype::addGlyph(llwchar wch) const
319{
320	if (mFTFace == NULL)
321		return FALSE;
322
323	llassert(!mIsFallback);
324	//lldebugs << "Adding new glyph for " << wch << " to font" << llendl;
325
326	FT_UInt glyph_index;
327
328	// Initialize char to glyph map
329	glyph_index = FT_Get_Char_Index(mFTFace, wch);
330	if (glyph_index == 0)
331	{
332		//llinfos << "Trying to add glyph from fallback font!" << llendl;
333		font_vector_t::const_iterator iter;
334		for(iter = mFallbackFonts.begin(); iter != mFallbackFonts.end(); iter++)
335		{
336			glyph_index = FT_Get_Char_Index((*iter)->mFTFace, wch);
337			if (glyph_index)
338			{
339				return addGlyphFromFont(*iter, wch, glyph_index);
340			}
341		}
342	}
343	
344	char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.find(wch);
345	if (iter == mCharGlyphInfoMap.end())
346	{
347		return addGlyphFromFont(this, wch, glyph_index);
348	}
349	return NULL;
350}
351
352LLFontGlyphInfo* LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, llwchar wch, U32 glyph_index) const
353{
354	if (mFTFace == NULL)
355		return NULL;
356
357	llassert(!mIsFallback);
358	fontp->renderGlyph(glyph_index);
359	S32 width = fontp->mFTFace->glyph->bitmap.width;
360	S32 height = fontp->mFTFace->glyph->bitmap.rows;
361
362	S32 pos_x, pos_y;
363	S32 bitmap_num;
364	mFontBitmapCachep->nextOpenPos(width, pos_x, pos_y, bitmap_num);
365	mAddGlyphCount++;
366
367	LLFontGlyphInfo* gi = new LLFontGlyphInfo(glyph_index);
368	gi->mXBitmapOffset = pos_x;
369	gi->mYBitmapOffset = pos_y;
370	gi->mBitmapNum = bitmap_num;
371	gi->mWidth = width;
372	gi->mHeight = height;
373	gi->mXBearing = fontp->mFTFace->glyph->bitmap_left;
374	gi->mYBearing = fontp->mFTFace->glyph->bitmap_top;
375	// Convert these from 26.6 units to float pixels.
376	gi->mXAdvance = fontp->mFTFace->glyph->advance.x / 64.f;
377	gi->mYAdvance = fontp->mFTFace->glyph->advance.y / 64.f;
378
379	insertGlyphInfo(wch, gi);
380
381	llassert(fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO
382	    || fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
383
384	if (fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO
385	    || fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY)
386	{
387		U8 *buffer_data = fontp->mFTFace->glyph->bitmap.buffer;
388		S32 buffer_row_stride = fontp->mFTFace->glyph->bitmap.pitch;
389		U8 *tmp_graydata = NULL;
390
391		if (fontp->mFTFace->glyph->bitmap.pixel_mode
392		    == FT_PIXEL_MODE_MONO)
393		{
394			// need to expand 1-bit bitmap to 8-bit graymap.
395			tmp_graydata = new U8[width * height];
396			S32 xpos, ypos;
397			for (ypos = 0; ypos < height; ++ypos)
398			{
399				S32 bm_row_offset = buffer_row_stride * ypos;
400				for (xpos = 0; xpos < width; ++xpos)
401				{
402					U32 bm_col_offsetbyte = xpos / 8;
403					U32 bm_col_offsetbit = 7 - (xpos % 8);
404					U32 bit =
405					!!(buffer_data[bm_row_offset
406						       + bm_col_offsetbyte
407					   ] & (1 << bm_col_offsetbit) );
408					tmp_graydata[width*ypos + xpos] =
409						255 * bit;
410				}
411			}
412			// use newly-built graymap.
413			buffer_data = tmp_graydata;
414			buffer_row_stride = width;
415		}
416
417		switch (mFontBitmapCachep->getNumComponents())
418		{
419		case 1:
420			mFontBitmapCachep->getImageRaw(bitmap_num)->setSubImage(pos_x,
421																	pos_y,
422																	width,
423																	height,
424																	buffer_data,
425																	buffer_row_stride,
426																	TRUE);
427			break;
428		case 2:
429			setSubImageLuminanceAlpha(pos_x,	
430									  pos_y,
431									  bitmap_num,
432									  width,
433									  height,
434									  buffer_data,
435									  buffer_row_stride);
436			break;
437		default:
438			break;
439		}
440
441		if (tmp_graydata)
442			delete[] tmp_graydata;
443	} else {
444		// we don't know how to handle this pixel format from FreeType;
445		// omit it from the font-image.
446	}
447	
448	LLImageGL *image_gl = mFontBitmapCachep->getImageGL(bitmap_num);
449	LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(bitmap_num);
450	image_gl->setSubImage(image_raw, 0, 0, image_gl->getWidth(), image_gl->getHeight());
451
452	return gi;
453}
454
455LLFontGlyphInfo* LLFontFreetype::getGlyphInfo(llwchar wch) const
456{
457	char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.find(wch);
458	if (iter != mCharGlyphInfoMap.end())
459	{
460		return iter->second;
461	}
462	else
463	{
464		// this glyph doesn't yet exist, so render it and return the result
465		return addGlyph(wch);
466	}
467}
468
469void LLFontFreetype::insertGlyphInfo(llwchar wch, LLFontGlyphInfo* gi) const
470{
471	char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.find(wch);
472	if (iter != mCharGlyphInfoMap.end())
473	{
474		delete iter->second;
475		iter->second = gi;
476	}
477	else
478	{
479		mCharGlyphInfoMap[wch] = gi;
480	}
481}
482
483void LLFontFreetype::renderGlyph(U32 glyph_index) const
484{
485	if (mFTFace == NULL)
486		return;
487
488	int error = FT_Load_Glyph(mFTFace, glyph_index, FT_LOAD_FORCE_AUTOHINT );
489	llassert(!error);
490
491	error = FT_Render_Glyph(mFTFace->glyph, gFontRenderMode);
492
493	mRenderGlyphCount++;
494	
495	llassert(!error);
496}
497
498void LLFontFreetype::reset(F32 vert_dpi, F32 horz_dpi)
499{
500	resetBitmapCache(); 
501	loadFace(mName, mPointSize, vert_dpi ,horz_dpi, mFontBitmapCachep->getNumComponents(), mIsFallback);
502	if (!mIsFallback)
503	{
504		// This is the head of the list - need to rebuild ourself and all fallbacks.
505		if (mFallbackFonts.empty())
506		{
507			llwarns << "LLFontGL::reset(), no fallback fonts present" << llendl;
508		}
509		else
510		{
511			for(font_vector_t::iterator it = mFallbackFonts.begin();
512				it != mFallbackFonts.end();
513				++it)
514			{
515				(*it)->reset(vert_dpi, horz_dpi);
516			}
517		}
518	}
519}
520
521void LLFontFreetype::resetBitmapCache()
522{
523	for_each(mCharGlyphInfoMap.begin(), mCharGlyphInfoMap.end(), DeletePairedPointer());
524	mCharGlyphInfoMap.clear();
525	mFontBitmapCachep->reset();
526
527	// Adding default glyph is skipped for fallback fonts here as well as in loadFace(). 
528	// This if was added as fix for EXT-4971.
529	if(!mIsFallback)
530	{
531		// Add the empty glyph
532		addGlyphFromFont(this, 0, 0);
533	}
534}
535
536void LLFontFreetype::destroyGL()
537{
538	mFontBitmapCachep->destroyGL();
539}
540
541const std::string &LLFontFreetype::getName() const
542{
543	return mName;
544}
545
546const LLPointer<LLFontBitmapCache> LLFontFreetype::getFontBitmapCache() const
547{
548	return mFontBitmapCachep;
549}
550
551void LLFontFreetype::setStyle(U8 style)
552{
553	mStyle = style;
554}
555
556U8 LLFontFreetype::getStyle() const
557{
558	return mStyle;
559}
560
561void LLFontFreetype::setSubImageLuminanceAlpha(U32 x, U32 y, U32 bitmap_num, U32 width, U32 height, U8 *data, S32 stride) const
562{
563	LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(bitmap_num);
564
565	llassert(!mIsFallback);
566	llassert(image_raw && (image_raw->getComponents() == 2));
567
568	
569	U8 *target = image_raw->getData();
570
571	if (!data)
572	{
573		return;
574	}
575
576	if (0 == stride)
577		stride = width;
578
579	U32 i, j;
580	U32 to_offset;
581	U32 from_offset;
582	U32 target_width = image_raw->getWidth();
583	for (i = 0; i < height; i++)
584	{
585		to_offset = (y + i)*target_width + x;
586		from_offset = (height - 1 - i)*stride;
587		for (j = 0; j < width; j++)
588		{
589			*(target + to_offset*2 + 1) = *(data + from_offset);
590			to_offset++;
591			from_offset++;
592		}
593	}
594}
595