1 /***************************************************************************
2  *   Copyright (C) 2007 by Pierre Marchand   *
3  *   pierre@oep-h.com   *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20 #include "fontitem.h"
21 #include "fmaltcontext.h"
22 #include "fmotf.h"
23 #include "fmencdata.h"
24 #include "fmfontdb.h"
25 #include "fmfontstrings.h"
26 #include "fmfreetypelib.h"
27 #include "fmglyphsview.h"
28 #include "glyphtosvghelper.h"
29 #include "typotek.h"
30 #include "fmbaseshaper.h"
31 #include "hyphenate/fmhyphenator.h"
32 #include "fmkernfeat.h"
33 #include "fmuniblocks.h"
34 
35 #include <cmath>
36 
37 #include <QDebug>
38 #include <QFileInfo>
39 #include <QGraphicsPixmapItem>
40 #include <QGraphicsObject>
41 #include <QGraphicsScene>
42 #include <QGraphicsView>
43 #include <QGraphicsPathItem>
44 #include <QGraphicsRectItem>
45 #include <QApplication>
46 #include <QPainter>
47 #include <QLocale>
48 #include <QTextCodec>
49 
50 #include <QProgressDialog>
51 
52 #include "QDebug"
53 
54 #include FT_XFREE86_H
55 #include FT_GLYPH_H
56 #include FT_OUTLINE_H
57 #include FT_SFNT_NAMES_H
58 #include FT_TYPE1_TABLES_H
59 #include FT_TRUETYPE_TABLES_H
60 #include FT_TRUETYPE_IDS_H
61 
62 // #include <QWaitCondition>
63 // #include <QMutex>
64 
65 int fm_num_face_opened = 0;
66 
67 QGraphicsScene *FontItem::theOneLineScene = 0;
68 
69 
70 
71 
72 
73 QList<int> FontItem::legitimateNonPathChars;
74 
75 QVector<QRgb> gray256Palette;
76 QVector<QRgb> invertedGray256Palette;
77 
78 // QWaitCondition theCondition;
79 // QMutex theMutex;
80 
81 unsigned int OTF_name_tag ( QString s );
82 
83 /** functions set for decomposition
84  */
85 
86 struct SizedPath{
87 	QPainterPath* p;
88 	double s;
89 };
90 
91 // an anticipation of further changes in Freetype
92 struct FM_Vector // :)
93 {
94 	double x;
95 	double y;
96 
FM_VectorFM_Vector97 	FM_Vector(const FT_Vector* vect)
98 	{
99 		x = double(vect->x);
100 		y = double(vect->y);
101 
102 // 		qDebug()<<"x26"<<vect26dot6->x<<"y26"<<vect26dot6->y <<"x"<<x<<"y"<<y;
103 	};
104 };
105 
_moveTo(const FT_Vector * to26,void * user)106 static int _moveTo ( const FT_Vector*  to26, void*   user )
107 {
108 	FM_Vector to(to26);
109 	SizedPath* sp = reinterpret_cast<SizedPath*> ( user );
110 	QPainterPath * p( sp->p );
111 	double sf( sp->s );
112 	p->moveTo ( to.x * sf , to.y * sf * -1.0 );
113 	return 0;
114 }
_lineTo(const FT_Vector * to26,void * user)115 static int _lineTo ( const FT_Vector*  to26, void*   user )
116 {
117 	FM_Vector to(to26);
118 	SizedPath* sp = reinterpret_cast<SizedPath*> ( user );
119 	QPainterPath * p( sp->p );
120 	double sf( sp->s );
121 	p->lineTo ( to.x * sf, to.y  * sf * -1.0 );
122 	return  0;
123 }
_conicTo(const FT_Vector * control26,const FT_Vector * to26,void * user)124 static int _conicTo ( const FT_Vector* control26, const FT_Vector*  to26, void*   user )
125 {
126 	FM_Vector control(control26);
127 	FM_Vector to(to26);
128 	SizedPath* sp = reinterpret_cast<SizedPath*> ( user );
129 	QPainterPath * p( sp->p );
130 	double sf( sp->s );
131 	p->quadTo ( control.x * sf,control.y * sf * -1.0,to.x * sf,to.y * sf * -1.0 );
132 	return 0;
133 }
_cubicTo(const FT_Vector * control126,const FT_Vector * control226,const FT_Vector * to26,void * user)134 static int _cubicTo ( const FT_Vector* control126, const FT_Vector* control226, const FT_Vector*  to26, void*   user )
135 {
136 	FM_Vector control1(control126);
137 	FM_Vector control2(control226);
138 	FM_Vector to(to26);
139 	SizedPath* sp = reinterpret_cast<SizedPath*> ( user );
140 	QPainterPath * p( sp->p );
141 	double sf( sp->s );
142 	p->cubicTo ( control1.x * sf,control1.y * sf * -1.0,control2.x * sf,control2.y * sf * -1.0,to.x * sf,to.y  * sf * -1.0);
143 	return 0;
144 }
145 
146 FT_Outline_Funcs outline_funcs=
147 {
148 	_moveTo,
149 	_lineTo,
150 	_conicTo,
151 	_cubicTo,
152 	0,
153 	0
154 };
155 /** **************************************************/
156 
157 
158 
fillLegitimateSpaces()159 void FontItem::fillLegitimateSpaces()
160 {
161 	legitimateNonPathChars << 0x0020 ;
162 	legitimateNonPathChars << 0x00A0 ;
163 	legitimateNonPathChars << 0x1680 ;
164 	legitimateNonPathChars << 0x180E ;
165 	legitimateNonPathChars << 0x2002 ;
166 	legitimateNonPathChars << 0x2003 ;
167 	legitimateNonPathChars << 0x2004 ;
168 	legitimateNonPathChars << 0x2005 ;
169 	legitimateNonPathChars << 0x2006 ;
170 	legitimateNonPathChars << 0x2007 ;
171 	legitimateNonPathChars << 0x2008 ;
172 	legitimateNonPathChars << 0x2009 ;
173 	legitimateNonPathChars << 0x200A ;
174 	legitimateNonPathChars << 0x200B ;
175 	legitimateNonPathChars << 0x200C ;
176 	legitimateNonPathChars << 0x200D ;
177 	legitimateNonPathChars << 0x202F ;
178 	legitimateNonPathChars << 0x205F ;
179 	legitimateNonPathChars << 0x2060 ;
180 	legitimateNonPathChars << 0x3000 ;
181 	legitimateNonPathChars << 0xFEFF ;
182 }
183 
184 
fill256Palette()185 void FontItem::fill256Palette()
186 {
187 // #ifdef   PLATFORM_APPLE
188 // 	for ( int i = 0; i < 256 ; ++i )
189 // 	{
190 // 		gray256Palette << qRgb (255-i, 255-i,255- i );
191 // 	}
192 // #else
193 	for ( int i = 0; i < 256 ; ++i )
194 	{
195 		gray256Palette << qRgba ( 0,0,0, i );
196 	}
197 // #endif
198 }
199 
fillInvertedPalette()200 void FontItem::fillInvertedPalette()
201 {
202 	for ( int i = 0; i < 256 ; ++i )
203 	{
204 		invertedGray256Palette << qRgb ( i , i,  i );
205 	}
206 }
207 
208 
209 
210 
FontItem(QString path,bool remote,bool faststart)211 FontItem::FontItem ( QString path , bool remote, bool faststart )
212 {
213 // 	qDebug()<<"FONT ITEM"<<path;
214 	m_valid = false;
215 	m_active = false;
216 	m_remote = remote;
217 	remoteCached = false;
218 	stopperDownload = false;
219 	m_face = 0;
220 	lastFace = 0;
221 	m_glyphsPerRow = 5;
222 	m_isEncoded = false;
223 	currentChar = -1;
224 	m_isOpenType = false;
225 	otf = 0;
226 	m_rasterFreetype = false;
227 	m_progression = PROGRESSION_LTR;
228 	m_shaperType = 1;
229 	renderReturnWidth = false;
230 	unitPerEm = 0;
231 	m_FTHintMode = 0;
232 	allIsRendered = false;
233 	isUpToDate = false;
234 	m_path = path;
235 
236 	/// STATIC INITIALISATIONS
237 
238 	if ( legitimateNonPathChars.isEmpty() )
239 		fillLegitimateSpaces();
240 	if ( gray256Palette.isEmpty() )
241 		fill256Palette();
242 	if ( invertedGray256Palette.isEmpty() )
243 		fillInvertedPalette();
244 	if ( !theOneLineScene )
245 	{
246 		theOneLineScene = new QGraphicsScene;
247 	}
248 	/// EndOF S I
249 
250 	if ( m_remote || faststart )
251 	{
252 		m_valid = true;
253 		return;
254 	}
255 
256 
257 	QFileInfo infopath ( m_path );
258 	m_name = infopath.fileName();
259 	m_fileSize = QString::number( infopath.size() , 10 ) ;
260 
261 	if ( ! ensureFace() )
262 	{
263 		return;
264 	}
265 
266 
267 	if ( infopath.suffix() == "pfb" || infopath.suffix() == "PFB" )
268 	{
269 		m_afm = m_path;
270 		if ( infopath.suffix() == "pfb" )
271 		{
272 			m_afm.replace ( ".pfb",".afm" );
273 			if ( !QFile::exists ( m_afm ) )
274 			{
275 				m_afm.replace ( ".afm" ,".AFM" );
276 				if ( !QFile::exists ( m_afm ) )
277 				{
278 					m_afm = "";
279 				}
280 			}
281 		}
282 		else if ( infopath.suffix() == "PFB" )
283 		{
284 			m_afm.replace ( ".PFB",".AFM" );
285 			if ( !QFile::exists ( m_afm ) )
286 			{
287 				m_afm.replace ( ".AFM" ,".afm" );
288 				if ( !QFile::exists ( m_afm ) )
289 				{
290 					m_afm = "";
291 				}
292 			}
293 		}
294 	}
295 
296 
297 	if ( testFlag ( m_face->face_flags, FT_FACE_FLAG_SFNT, "1","0" ) == "1" )
298 	{
299 		m_isOpenType = true;
300 	}
301 
302 	if(m_isOpenType)
303 		moreInfo_sfnt();
304 	else
305 		moreInfo_type1();
306 
307 	m_type = FT_Get_X11_Font_Format ( m_face );
308 // 	if ( typotek::getInstance()->familySchemeFreetype() || !m_isOpenType )
309 	{
310 		m_family = m_face->family_name;
311 		m_variant = m_face->style_name;
312 	}
313 // 	else
314 // 	{
315 // 		m_family = getAlternateFamilyName();
316 // 		m_variant = getAlternateVariantName();
317 // 	}
318 	m_numGlyphs = m_face->num_glyphs;
319 	m_numFaces = m_face->num_faces;
320 
321 // 	for ( int i = 0 ;i < m_face->num_charmaps; ++i )
322 // 	{
323 // 		m_charsets << charsetMap[m_face->charmaps[i]->encoding];
324 // 	}
325 
326 
327 // 	m_lock = false;
328 	pixList.clear();
329 
330 	if ( m_family.isEmpty() )
331 		return;
332 	if ( m_variant.isEmpty() )
333 		return;
334 
335 	m_valid = true;
336 	releaseFace();
337 }
338 
FontItem(QString path,QString family,QString variant,QString type,bool active)339 FontItem::FontItem(QString path, QString family, QString variant, QString type,bool active)
340 {
341 	m_valid = true;
342 	m_remote = false;
343 	remoteCached = false;
344 	stopperDownload = false;
345 	m_face = 0;
346 	lastFace = 0;
347 	m_glyphsPerRow = 5;
348 	m_isEncoded = false;
349 	currentChar = -1;
350 	m_isOpenType = false;
351 	otf = 0;
352 	m_rasterFreetype = false;
353 	m_progression = PROGRESSION_LTR;
354 	m_shaperType = 1;
355 	renderReturnWidth = false;
356 	unitPerEm = 0;
357 	m_FTHintMode = 0;
358 // 	m_lock = false;
359 	allIsRendered = false;
360 	isUpToDate = false;
361 
362 
363 	if ( legitimateNonPathChars.isEmpty() )
364 		fillLegitimateSpaces();
365 	if ( gray256Palette.isEmpty() )
366 		fill256Palette();
367 	if ( invertedGray256Palette.isEmpty() )
368 		fillInvertedPalette();
369 	if ( !theOneLineScene )
370 	{
371 		theOneLineScene = new QGraphicsScene;
372 	}
373 
374 	m_path = path;
375 	m_family = family;
376 	m_variant = variant;
377 	m_active = active;
378 	m_type = type;
379 }
380 
Clone()381 FontItem * FontItem::Clone()
382 {
383 	FontItem *fitem = new FontItem ( m_path, m_family, m_variant, m_type, m_active );
384 	return fitem;
385 }
386 
updateItem()387 void FontItem::updateItem()
388 {
389 	if(isUpToDate)
390 		return;
391 	QFileInfo infopath ( m_path );
392 	m_name = infopath.fileName();
393 	if ( ! ensureFace() )
394 	{
395 		return;
396 	}
397 	if ( infopath.suffix() == "pfb" || infopath.suffix() == "PFB" )
398 	{
399 		m_afm = m_path;
400 		if ( infopath.suffix() == "pfb" )
401 		{
402 			m_afm.replace ( ".pfb",".afm" );
403 			if ( !QFile::exists ( m_afm ) )
404 			{
405 				m_afm.replace ( ".afm" ,".AFM" );
406 				if ( !QFile::exists ( m_afm ) )
407 				{
408 					m_afm = "";
409 				}
410 			}
411 		}
412 		else if ( infopath.suffix() == "PFB" )
413 		{
414 			m_afm.replace ( ".PFB",".AFM" );
415 			if ( !QFile::exists ( m_afm ) )
416 			{
417 				m_afm.replace ( ".AFM" ,".afm" );
418 				if ( !QFile::exists ( m_afm ) )
419 				{
420 					m_afm = "";
421 				}
422 			}
423 		}
424 	}
425 
426 
427 	if ( testFlag ( m_face->face_flags, FT_FACE_FLAG_SFNT, "1","0" ) == "1" )
428 	{
429 		m_isOpenType = true;
430 	}
431 
432 	m_type = FT_Get_X11_Font_Format ( m_face );
433 	m_family = m_face->family_name;
434 	m_variant = m_face->style_name;
435 	m_numGlyphs = m_face->num_glyphs;
436 	m_numFaces = m_face->num_faces;
437 
438 	releaseFace();
439 	isUpToDate = true;
440 }
441 
~FontItem()442 FontItem::~FontItem()
443 {
444 	if ( m_isOpenType && otf )
445 	{
446 // 		delete otf;
447 	}
448 }
449 
450 
encodeFace()451 void FontItem::encodeFace()
452 {
453 	if(!m_face)
454 		return;
455 
456 	m_charsets.clear();
457 	m_unicodeBuiltIn = (m_face->charmap == NULL) ? false : true ;
458 	if(QString(FT_Get_X11_Font_Format(m_face)) == QString("Type 1"))
459 		m_unicodeBuiltIn = false;
460 
461 	QMap<FT_Encoding, FT_CharMap> cmaps;
462 	for(int u = 0; u < m_face->num_charmaps; u++)
463 	{
464 		cmaps [ m_face->charmaps[u]->encoding ] = m_face->charmaps[u];
465 	}
466 
467 	bool mapped(false);
468 	// Stop kidding
469 	if (/* (!isType1) && UnicodeBuiltIn && */cmaps.contains( FT_ENCODING_UNICODE ) )
470 	{
471 		FT_Set_Charmap(m_face, cmaps[FT_ENCODING_UNICODE]);
472 		m_charsets << FT_ENCODING_UNICODE;
473 		mapped = true;
474 		m_isEncoded = true;
475 		m_currentEncoding = FT_ENCODING_UNICODE;
476 	}
477 	// uncomment below to get Unicode cmap synthetized by FT
478 // 	else if(cmaps.contains( FT_ENCODING_UNICODE ))
479 // 	{
480 // 		FT_Set_Charmap(m_face, cmaps[FT_ENCODING_UNICODE]);
481 // 		m_charsets << FontStrings::Encoding(FT_ENCODING_UNICODE) +"*";
482 // 		mapped = true;
483 // 		cmaps.remove(FT_ENCODING_UNICODE);
484 // 		m_isEncoded = true;
485 // 	}
486 	foreach(FT_Encoding e, cmaps.keys())
487 	{
488 // 		QString cs(FontStrings::Encoding(e));
489 // 		if(isType1 && (e == FT_ENCODING_UNICODE))
490 // 			continue;
491 		if(!m_charsets.contains(e))
492 			m_charsets << e;
493 		if(!mapped)
494 		{
495 			FT_Set_Charmap(m_face, cmaps[e]);
496 			mapped = true;
497 			m_isEncoded = true;
498 			m_currentEncoding = e;
499 		}
500 	}
501 }
502 
ensureFace()503 bool FontItem::ensureFace()
504 {
505 	FT_Library ftlib = FMFreetypeLib::lib(thread());
506 //	qDebug()<<"FontItem::ensureFace"<<thread();
507 
508 	if ( m_face )
509 	{
510 		++facesRef;
511 		return true;
512 	}
513 	QString trueFile ( m_remote ? remoteHerePath : m_path );
514 	ft_error = FT_New_Face ( ftlib, trueFile.toLocal8Bit() , 0, &m_face );
515 	if ( ft_error )
516 	{
517 		qDebug() << "Error loading face [" << trueFile <<"]";
518 		return false;
519 	}
520 	encodeFace();
521 	if ( spaceIndex.isEmpty() )
522 	{
523 		int gIndex ( 0 );
524 		for ( int i ( 0 ); i < legitimateNonPathChars.count(); ++i )
525 		{
526 			gIndex =   FT_Get_Char_Index ( m_face , legitimateNonPathChars[i] );
527 			if ( gIndex )
528 			{
529 				spaceIndex << gIndex;
530 			}
531 		}
532 	}
533 	unitPerEm = m_face->units_per_EM;
534 	m_glyph = m_face->glyph;
535 	facesRef = 1;
536 	++fm_num_face_opened;
537 	return true;
538 }
539 
releaseFace()540 void FontItem::releaseFace()
541 {
542 	if ( m_face )
543 	{
544 		--facesRef;
545 		if ( facesRef == 0 )
546 		{
547 			FT_Done_Face ( m_face );
548 			m_face = 0;
549 			--fm_num_face_opened;
550 		}
551 	}
552 }
553 
glyphsCount() const554 int FontItem::glyphsCount() const
555 {
556 	if(m_numGlyphs > 0) // this is normal case
557 	{
558 		return m_numGlyphs;
559 	}
560 	FontItem * that(const_cast<FontItem*>(this));
561 	that->ensureFace();
562 	that->m_numGlyphs = m_face->num_glyphs;
563 	that->releaseFace();
564 	return m_numGlyphs;
565 }
566 
testFlag(long flag,long against,QString yes,QString no)567 QString FontItem::testFlag ( long flag, long against, QString yes, QString no )
568 {
569 	if ( ( flag & against ) == against )
570 		return yes;
571 	else
572 		return no;
573 }
574 
575 // QString FontItem::value ( QString k )
576 // {
577 // 	// I don’t know if something relies o it so I keep it, for the moment.
578 // 	if ( k == "family" )
579 // 		return m_family;
580 // 	else if ( k == "variant" )
581 // 		return m_variant;
582 //
583 // 	// 0 is default language
584 // 	// TODO inspect all available languages
585 // // 	if(moreInfo.isEmpty())
586 // // 	{
587 // // 		if(isOpenType())
588 // // 			moreInfo_sfnt();
589 // // 		else
590 // // 			moreInfo_type1();
591 // // 	}
592 // 	FontInfoMap moreInfo( FMFontDb::DB()->getInfoMap(m_path) );
593 // 	QMap<int, QString> namap ( moreInfo.value ( 0 ) );
594 // 	return namap.value ( name_meaning.indexOf( k ) );
595 // }
596 
597 // QString FontItem::panose ( QString k )
598 // {
599 // 	return panoseInfo.value ( k );
600 // }
601 
602 
name()603 QString FontItem::name()
604 {
605 	return m_name;
606 }
607 
itemFromChar(int charcode,double size)608 QGraphicsPathItem * FontItem::itemFromChar ( int charcode, double size )
609 {
610 
611 	if(!ensureFace())
612 		return 0;
613 	uint glyphIndex = 0;
614 	currentChar = charcode;
615 	glyphIndex = FT_Get_Char_Index ( m_face, charcode );
616 
617 	QGraphicsPathItem * ret(itemFromGindex ( glyphIndex,size ));
618 	releaseFace();
619 	return ret;
620 
621 }
622 
itemFromGindex(int index,double size)623 QGraphicsPathItem * FontItem::itemFromGindex ( int index, double size )
624 {
625 	if(!ensureFace())
626 		return 0;
627 	int charcode = index ;
628 	double scalefactor = size / m_face->units_per_EM;
629 	ft_error = FT_Load_Glyph ( m_face, charcode  , FT_LOAD_NO_SCALE );
630 	if ( ft_error )
631 	{
632 		QPainterPath glyphPath;
633 		glyphPath.addRect ( 0.0,0.0, size, size );
634 		QGraphicsPathItem *glyph = new  QGraphicsPathItem;
635 		glyph->setBrush ( QBrush ( Qt::red ) );
636 		glyph->setPath ( glyphPath );
637 		glyph->setData ( GLYPH_DATA_GLYPH, index);
638 		glyph->setData ( GLYPH_DATA_HADVANCE , ( double ) size * scalefactor);
639 		glyph->setData ( GLYPH_DATA_HADVANCE_SCALED , ( double ) size );
640 		glyph->setData ( GLYPH_DATA_ERROR , true );
641 		releaseFace();
642 		return glyph;
643 	}
644 
645 	FT_Outline *outline = &m_glyph->outline;
646 	QPainterPath glyphPath ( QPointF ( 0.0,0.0 ) );
647 	SizedPath sp;
648 	sp.p = &glyphPath;
649 	sp.s = scalefactor;
650 	FT_Outline_Decompose ( outline, &outline_funcs, &sp );
651 	glyphPath.closeSubpath();
652 	QGraphicsPathItem *glyph = new  QGraphicsPathItem;
653 
654 	if ( glyphPath.elementCount() < 3 && !spaceIndex.contains ( index ) )
655 	{
656 		QBrush brush ( Qt::SolidPattern );
657 		brush.setColor ( Qt::red );
658 		QPen pen ( brush, 0 );
659 		QPainterPath errPath;
660 		errPath.addRect ( 0.0,-size, size , size );
661 		glyph->setBrush ( brush );
662 		glyph->setPen ( pen );
663 		glyph->setPath ( errPath );
664 		glyph->setData ( GLYPH_DATA_HADVANCE , ( double ) m_glyph->metrics.horiAdvance   );
665 		glyph->setData ( GLYPH_DATA_HADVANCE_SCALED , ( double ) m_glyph->metrics.horiAdvance  *scalefactor);
666 		glyph->setData ( GLYPH_DATA_GLYPH, index);
667 		glyph->setData ( GLYPH_DATA_ERROR , true );
668 	}
669 	else
670 	{
671 		glyph->setBrush ( QBrush ( Qt::SolidPattern ) );
672 		glyph->setPath ( glyphPath );
673 		glyph->setData ( GLYPH_DATA_GLYPH, index);
674 		glyph->setData ( GLYPH_DATA_HADVANCE , ( double ) m_glyph->metrics.horiAdvance );
675 		glyph->setData ( GLYPH_DATA_HADVANCE_SCALED , ( double ) m_glyph->metrics.horiAdvance * scalefactor);
676 		glyph->setData ( 5, ( double ) m_glyph->metrics.vertAdvance );
677 		glyph->setData ( GLYPH_DATA_ERROR , false );
678 // 		glyph->scale ( scalefactor,-scalefactor );
679 	}
680 	releaseFace();
681 	return glyph;
682 }
683 
itemFromCharPix(int charcode,double size)684 QGraphicsPixmapItem * FontItem::itemFromCharPix ( int charcode, double size )
685 {
686 	if(!ensureFace())
687 		return 0;
688 	uint glyphIndex = 0;
689 	currentChar = charcode;
690 	glyphIndex = FT_Get_Char_Index ( m_face, charcode );
691 
692 	releaseFace();
693 	return itemFromGindexPix ( glyphIndex,size );
694 
695 }
696 
697 
itemFromGindexPix(int index,double size)698 QGraphicsPixmapItem * FontItem::itemFromGindexPix ( int index, double size )
699 {
700 	if ( !ensureFace() )
701 		return 0;
702 	int charcode = index ;
703 
704 	double scaleFactor = size / m_face->units_per_EM;
705 
706 	// Set size
707 	FT_Set_Char_Size ( m_face,
708 	                   qRound( size  * 64 ),
709 	                   0,
710 			   typotek::getInstance()->getDpiX(),
711 			   typotek::getInstance()->getDpiY() );
712 
713 	// Grab metrics in FONT UNIT
714 	ft_error = FT_Load_Glyph ( m_face,
715 	                           charcode  ,
716 	                           FT_LOAD_NO_SCALE  );
717 	if ( ft_error )
718 	{
719 		QPixmap square ( qRound(size) , qRound(size) );
720 		square.fill ( Qt::red );
721 		QGraphicsPixmapItem *glyph = new QGraphicsPixmapItem ( square );
722 		glyph->setData ( GLYPH_DATA_GLYPH ,index );
723 		glyph->setData ( GLYPH_DATA_BITMAPLEFT , 0 );
724 		glyph->setData ( GLYPH_DATA_BITMAPTOP,size );
725 		glyph->setData ( GLYPH_DATA_HADVANCE ,size / ( size / m_face->units_per_EM ) );
726 		releaseFace();
727 		return glyph;
728 	}
729 
730 	double takeAdvanceBeforeRender = m_glyph->metrics.horiAdvance * ( typotek::getInstance()->getDpiX() / 72.0 );
731 	double takeVertAdvanceBeforeRender = m_glyph->metrics.vertAdvance * ( typotek::getInstance()->getDpiY() / 72.0 );
732 	double takeLeftBeforeRender = double(m_glyph->metrics.horiBearingX) * ( typotek::getInstance()->getDpiX() / 72.0 );
733 
734 // 	if(m_FTHintMode != FT_LOAD_NO_HINTING)
735 	{
736 		ft_error = FT_Load_Glyph ( m_face, charcode  , FT_LOAD_DEFAULT | m_FTHintMode  );
737 	}
738 	// Render the glyph into a grayscale bitmap
739 	ft_error = FT_Render_Glyph ( m_face->glyph, FT_RENDER_MODE_NORMAL );
740 	if ( ft_error )
741 	{
742 		QPixmap square ( qRound(size) , qRound(size) );
743 		square.fill ( Qt::red );
744 		QGraphicsPixmapItem *glyph = new QGraphicsPixmapItem ( square );
745 		glyph->setData ( GLYPH_DATA_GLYPH , index );
746 		glyph->setData ( GLYPH_DATA_BITMAPLEFT , 0 );
747 		glyph->setData ( GLYPH_DATA_BITMAPTOP,size );
748 		glyph->setData ( GLYPH_DATA_HADVANCE ,size  / ( size / m_face->units_per_EM ) );
749 		releaseFace();
750 		return glyph;
751 	}
752 
753 
754 	QImage img ( glyphImage() );
755 	QGraphicsPixmapItem *glyph = new  QGraphicsPixmapItem;
756 
757 	if ( img.isNull() && !spaceIndex.contains ( index ) )
758 	{
759 		QPixmap square ( qRound(size) , qRound(size) );
760 		square.fill ( Qt::red );
761 		glyph->setPixmap ( square );
762 		glyph->setData ( GLYPH_DATA_GLYPH , index );
763 		glyph->setData ( GLYPH_DATA_BITMAPLEFT , 0 );
764 		glyph->setData ( GLYPH_DATA_BITMAPTOP,size );
765 		glyph->setData ( GLYPH_DATA_HADVANCE ,size / ( size / m_face->units_per_EM ) );
766 	}
767 	else
768 	{
769 #ifndef PLATFORM_APPLE
770 		glyph->setPixmap ( QPixmap::fromImage ( img ) );
771 #else
772 		QPixmap aPix ( img.width(), img.height() );
773 		aPix.fill ( QColor ( 0,0,0,0 ) );
774 		QPainter aPainter ( &aPix );
775 		aPainter.drawImage ( 0,0, img );
776 		glyph->setPixmap ( aPix );
777 #endif
778 		// we need to transport more data
779 		glyph->setData ( GLYPH_DATA_GLYPH , index );
780 		glyph->setData ( GLYPH_DATA_BITMAPLEFT , takeLeftBeforeRender );
781 		glyph->setData ( GLYPH_DATA_BITMAPTOP , double(m_face->glyph->bitmap_top) );
782 		glyph->setData ( GLYPH_DATA_HADVANCE , takeAdvanceBeforeRender );
783 		glyph->setData ( GLYPH_DATA_VADVANCE , takeVertAdvanceBeforeRender );
784 	}
785 
786 	releaseFace();
787 	return glyph;
788 }
789 
itemFromGindexPix_mt(int index,double size)790 MetaGlyphItem * FontItem::itemFromGindexPix_mt(int index, double size)
791 {
792 	if ( !ensureFace() )
793 		return 0;
794 	int charcode = index ;
795 //	qDebug()<<"FontItem::itemFromGindexPix_mt"<< thread();
796 	MetaGlyphItem * glyph = new MetaGlyphItem;
797 	double scaleFactor = size / m_face->units_per_EM;
798 
799 	// Set size
800 	FT_Set_Char_Size ( m_face,
801 			   qRound( size  * 64 ),
802 			   0,
803 			   typotek::getInstance()->getDpiX(),
804 			   typotek::getInstance()->getDpiY() );
805 
806 	// Grab metrics in FONT UNIT
807 	ft_error = FT_Load_Glyph ( m_face,
808 				   charcode  ,
809 				   FT_LOAD_NO_SCALE  );
810 	if ( ft_error )
811 	{
812 		glyph->setMetaData ( GLYPH_DATA_GLYPH ,index );
813 		glyph->setMetaData ( GLYPH_DATA_BITMAPLEFT , 0 );
814 		glyph->setMetaData ( GLYPH_DATA_BITMAPTOP,size );
815 		glyph->setMetaData ( GLYPH_DATA_HADVANCE ,size / scaleFactor );
816 		releaseFace();
817 		return glyph;
818 	}
819 
820 	double takeAdvanceBeforeRender = m_glyph->metrics.horiAdvance * ( typotek::getInstance()->getDpiX() / 72.0 );
821 	double takeVertAdvanceBeforeRender = m_glyph->metrics.vertAdvance * ( typotek::getInstance()->getDpiX() / 72.0 );
822 	double takeLeftBeforeRender = ( double ) m_glyph->metrics.horiBearingX * ( typotek::getInstance()->getDpiX() / 72.0 );
823 
824 // 	if(m_FTHintMode != FT_LOAD_NO_HINTING)
825 	{
826 		ft_error = FT_Load_Glyph ( m_face, charcode  , FT_LOAD_DEFAULT | m_FTHintMode  );
827 	}
828 	// Render the glyph into a grayscale bitmap
829 	ft_error = FT_Render_Glyph ( m_face->glyph, FT_RENDER_MODE_NORMAL );
830 	if ( ft_error )
831 	{
832 		glyph->setMetaData ( GLYPH_DATA_GLYPH , index );
833 		glyph->setMetaData ( GLYPH_DATA_BITMAPLEFT , 0 );
834 		glyph->setMetaData ( GLYPH_DATA_BITMAPTOP,size );
835 		glyph->setMetaData ( GLYPH_DATA_HADVANCE ,size  / scaleFactor );
836 		releaseFace();
837 		return glyph;
838 	}
839 
840 
841 	QImage img ( glyphImage() );
842 
843 	if ( img.isNull() && !spaceIndex.contains ( index ) )
844 	{
845 		glyph->setMetaData ( GLYPH_DATA_GLYPH , index );
846 		glyph->setMetaData ( GLYPH_DATA_BITMAPLEFT , 0 );
847 		glyph->setMetaData ( GLYPH_DATA_BITMAPTOP,size );
848 		glyph->setMetaData ( GLYPH_DATA_HADVANCE ,size /scaleFactor  );
849 	}
850 	else
851 	{
852 		glyph->setMetaData ( GLYPH_DATA_GLYPH , index );
853 		glyph->setMetaData ( GLYPH_DATA_BITMAPLEFT , takeLeftBeforeRender );
854 		glyph->setMetaData ( GLYPH_DATA_BITMAPTOP , double(m_face->glyph->bitmap_top) );
855 		glyph->setMetaData ( GLYPH_DATA_HADVANCE , takeAdvanceBeforeRender );
856 		glyph->setMetaData ( GLYPH_DATA_VADVANCE , takeVertAdvanceBeforeRender );
857 	}
858 
859 	releaseFace();
860 	return glyph;
861 }
862 
charImage(int charcode,double size)863 QImage FontItem::charImage(int charcode, double size)
864 {
865 	if(!ensureFace())
866 		return QImage();
867 
868 	// Set size
869 	FT_Set_Char_Size ( m_face,  qRound( size  * 64 ), 0, typotek::getInstance()->getDpiX(),typotek::getInstance()->getDpiY() );
870 	if(FT_Load_Char( m_face, charcode , FT_LOAD_DEFAULT))
871 	{
872 		releaseFace();
873 		return QImage();
874 	}
875 	if(FT_Render_Glyph ( m_face->glyph, FT_RENDER_MODE_NORMAL ))
876 	{
877 		releaseFace();
878 		return QImage();
879 	}
880 
881 
882 	QImage cImg( glyphImage() );
883 	releaseFace();
884 	return cImg;
885 }
886 
glyphImage(int index,double size)887 QImage FontItem::glyphImage(int index, double size)
888 {
889 	if(!ensureFace())
890 		return QImage();
891 
892 	// Set size
893 	FT_Set_Char_Size ( m_face,  qRound( size  * 64 ), 0, typotek::getInstance()->getDpiX(),typotek::getInstance()->getDpiY() );
894 	if(FT_Load_Glyph( m_face, index , FT_LOAD_DEFAULT))
895 	{
896 		releaseFace();
897 		return QImage();
898 	}
899 	if(FT_Render_Glyph ( m_face->glyph, FT_RENDER_MODE_NORMAL ))
900 	{
901 		releaseFace();
902 		return QImage();
903 	}
904 
905 
906 	QImage cImg( glyphImage() );
907 	releaseFace();
908 	return cImg;
909 }
910 /// Nature line
renderLine(QGraphicsScene * scene,QString spec,QPointF origine,double lineWidth,double fsize,double zindex)911 double FontItem::renderLine ( QGraphicsScene * scene,
912                               QString spec,
913                               QPointF origine,
914                               double lineWidth,
915                               double fsize ,
916 			      double zindex )
917 {
918 // 	qDebug() <<fancyName() <<"::"<<"renderLine("<<scene<<spec<<lineWidth<<fsize<<zindex<<record<<")";
919 	double retValue ( 0.0 );
920 	if ( spec.isEmpty() )
921 		return retValue;
922 
923 	ensureFace();
924 
925 	double sizz = fsize;
926 	double scalefactor = sizz / m_face->units_per_EM;
927 	double pWidth = lineWidth ;
928 	const double distance = 20;
929 	QPointF pen ( origine );
930 	if ( m_rasterFreetype )
931 	{
932 		QList<QGraphicsPixmapItem*> mayBeRemoved;
933 		for ( int i=0; i < spec.length(); ++i )
934 		{
935 			QGraphicsPixmapItem *glyph = itemFromCharPix ( spec.at ( i ).unicode(), sizz );
936 			if( spec.at(i).category() == QChar::Separator_Space )
937 			{
938 				mayBeRemoved.clear();
939 			}
940 			if ( !glyph )
941 			{
942 				continue;
943 			}
944 			if ( m_progression == PROGRESSION_RTL )
945 			{
946 				pen.rx() -= ( glyph->data ( GLYPH_DATA_HADVANCE ).toDouble() + glyph->data ( GLYPH_DATA_BITMAPLEFT ).toDouble() ) * scalefactor;
947 				pWidth -= glyph->data ( GLYPH_DATA_HADVANCE ).toDouble() * scalefactor;
948 				if ( pWidth < distance )
949 				{
950 					delete glyph;
951 
952 					retValue -= mayBeRemoved.count() - 1;
953 					foreach(QGraphicsPixmapItem *rm, mayBeRemoved)
954 					{
955 						scene->removeItem( rm );
956 						delete rm;
957 					}
958 
959 					break;
960 				}
961 			}
962 			else if ( m_progression == PROGRESSION_BTT )
963 			{
964 				pen.ry() -=  glyph->data ( GLYPH_DATA_VADVANCE ).toDouble() * scalefactor;
965 				pWidth -=  glyph->data ( GLYPH_DATA_VADVANCE ).toDouble() * scalefactor;
966 				if ( pWidth < distance )
967 				{
968 					delete glyph;
969 
970 					retValue -= mayBeRemoved.count() - 1;
971 					foreach(QGraphicsPixmapItem *rm, mayBeRemoved)
972 					{
973 						scene->removeItem( rm );
974 						delete rm;
975 					}
976 
977 					break;
978 				}
979 			}
980 			else if ( m_progression == PROGRESSION_LTR )
981 			{
982 				pWidth -= glyph->data ( GLYPH_DATA_HADVANCE ).toDouble() * scalefactor;
983 				if ( pWidth < distance )
984 				{
985 					delete glyph;
986 
987 					retValue -= mayBeRemoved.count() - 1;
988 					foreach(QGraphicsPixmapItem *rm, mayBeRemoved)
989 					{
990 						scene->removeItem( rm );
991 						delete rm;
992 					}
993 
994 					break;
995 				}
996 			}
997 			else if ( m_progression == PROGRESSION_TTB )
998 			{
999 				pWidth -=  glyph->data ( GLYPH_DATA_VADVANCE ).toDouble() * scalefactor;
1000 				if ( pWidth < distance )
1001 				{
1002 					delete glyph;
1003 
1004 					retValue -= mayBeRemoved.count() - 1;
1005 					foreach(QGraphicsPixmapItem *rm, mayBeRemoved)
1006 					{
1007 						scene->removeItem( rm );
1008 						delete rm;
1009 					}
1010 
1011 					break;
1012 				}
1013 			}
1014 			if(renderReturnWidth)
1015 				retValue += glyph->data ( GLYPH_DATA_HADVANCE ).toDouble() * scalefactor;
1016 
1017 			/************************************/
1018 
1019 			mayBeRemoved.append(glyph);
1020 
1021 			scene->addItem ( glyph );
1022 
1023 			if(renderReturnWidth)
1024 				retValue += glyph->data ( GLYPH_DATA_HADVANCE ).toDouble() * scalefactor;
1025 			else
1026 				retValue += 1;
1027 
1028 			glyph->setPos ( pen.x() + glyph->data ( GLYPH_DATA_BITMAPLEFT ).toDouble() * scalefactor, pen.y() - glyph->data ( GLYPH_DATA_BITMAPTOP ).toInt() );
1029 			glyph->setZValue ( zindex );
1030 			glyph->setData ( GLYPH_DATA_GLYPH ,"glyph" );
1031 			glyph->setData ( GLYPH_DATA_FONTNAME , fancyName() );
1032 			/************************************/
1033 
1034 			if ( m_progression == PROGRESSION_LTR )
1035 				pen.rx() += glyph->data ( GLYPH_DATA_HADVANCE ).toDouble() * scalefactor;
1036 			else if ( m_progression == PROGRESSION_TTB )
1037 			{
1038 				pen.ry() +=  glyph->data ( GLYPH_DATA_VADVANCE ).toDouble() * scalefactor;
1039 			}
1040 		}
1041 	}
1042 	else
1043 	{
1044 		QList<QGraphicsPathItem*> mayBeRemoved;
1045 		for ( int i=0; i < spec.length(); ++i )
1046 		{
1047 //			if ( !scene->sceneRect().contains ( pen ) && record )
1048 //				break;
1049 			QGraphicsPathItem *glyph = itemFromChar ( spec.at ( i ).unicode(), sizz );
1050 			if ( !glyph )
1051 				continue;
1052 			if( spec.at(i).category() == QChar::Separator_Space )
1053 			{
1054 				mayBeRemoved.clear();
1055 			}
1056 			if ( m_progression == PROGRESSION_RTL )
1057 			{
1058 				pen.rx() -= glyph->data ( GLYPH_DATA_HADVANCE ).toDouble() * scalefactor;
1059 
1060 				pWidth -= glyph->data ( GLYPH_DATA_HADVANCE ).toDouble() * scalefactor;
1061 				if ( pWidth < distance )
1062 				{
1063 					delete glyph;
1064 
1065 					retValue -= mayBeRemoved.count() - 1;
1066 					foreach(QGraphicsPathItem *rm, mayBeRemoved)
1067 					{
1068 						scene->removeItem( rm );
1069 						delete rm;
1070 					}
1071 
1072 					break;
1073 				}
1074 			}
1075 			else if ( m_progression == PROGRESSION_BTT )
1076 			{
1077 				pen.ry() -=  glyph->data ( GLYPH_DATA_VADVANCE ).toDouble() * scalefactor;
1078 				pWidth -=  glyph->data ( GLYPH_DATA_VADVANCE ).toDouble() * scalefactor;
1079 				if ( pWidth < distance )
1080 				{
1081 					delete glyph;
1082 
1083 					retValue -= mayBeRemoved.count() - 1;
1084 					foreach(QGraphicsPathItem *rm, mayBeRemoved)
1085 					{
1086 						scene->removeItem( rm );
1087 						delete rm;
1088 					}
1089 
1090 					break;
1091 				}
1092 			}
1093 			else if ( m_progression == PROGRESSION_LTR )
1094 			{
1095 				pWidth -= glyph->data ( GLYPH_DATA_HADVANCE ).toDouble() * scalefactor;
1096 				if ( pWidth < distance )
1097 				{
1098 					delete glyph;
1099 
1100 					retValue -= mayBeRemoved.count() - 1;
1101 					foreach(QGraphicsPathItem *rm, mayBeRemoved)
1102 					{
1103 						scene->removeItem( rm );
1104 						delete rm;
1105 					}
1106 
1107 					break;
1108 				}
1109 			}
1110 			else if ( m_progression == PROGRESSION_TTB )
1111 			{
1112 				pWidth -=  glyph->data ( GLYPH_DATA_VADVANCE ).toDouble() * scalefactor;
1113 				if ( pWidth < distance )
1114 				{
1115 					delete glyph;
1116 
1117 					retValue -= mayBeRemoved.count() - 1;
1118 					foreach(QGraphicsPathItem *rm, mayBeRemoved)
1119 					{
1120 						scene->removeItem( rm );
1121 						delete rm;
1122 					}
1123 
1124 					break;
1125 				}
1126 			}
1127 
1128 			/*********************************/
1129 			scene->addItem ( glyph );
1130 			glyph->setPen(Qt::NoPen);
1131 
1132 			mayBeRemoved.append(glyph);
1133 
1134 			if(renderReturnWidth)
1135 				retValue += glyph->data ( GLYPH_DATA_HADVANCE ).toDouble() * scalefactor;
1136 			else
1137 				retValue += 1;
1138 
1139 			glyph->setPos ( pen );
1140 			glyph->setZValue ( zindex );
1141 			glyph->setData ( GLYPH_DATA_GLYPH ,"glyph" );
1142 			glyph->setData ( GLYPH_DATA_FONTNAME , fancyName() );
1143 			/*********************************/
1144 
1145 			if ( m_progression == PROGRESSION_LTR )
1146 			{
1147 				pen.rx() += glyph->data ( GLYPH_DATA_HADVANCE ).toDouble() * scalefactor;
1148 			}
1149 			else if ( m_progression == PROGRESSION_TTB )
1150 			{
1151 				pen.ry() +=  glyph->data ( GLYPH_DATA_VADVANCE ).toDouble() * scalefactor;
1152 			}
1153 		}
1154 	}
1155 
1156 	releaseFace();
1157 	return retValue;
1158 }
1159 
1160 /// Featured line
renderLine(OTFSet set,QGraphicsScene * scene,QString spec,QPointF origine,double lineWidth,double fsize)1161 double FontItem::renderLine ( OTFSet set, QGraphicsScene * scene, QString spec, QPointF origine,double lineWidth, double fsize)
1162 {
1163 // 	qDebug()<<"Featured("<< spec <<")";
1164 	double retValue ( 0.0 );
1165 	if ( spec.isEmpty() )
1166 		return retValue;
1167 	if ( !m_isOpenType )
1168 		return retValue;
1169 	ensureFace();
1170 
1171 	otf = new FMOtf ( m_face, 0x10000 );// You think "What’s this 0x10000?", so am I! Just accept Harfbuzz black magic :)
1172 	if ( !otf )
1173 		return retValue;
1174 	double sizz = fsize;
1175 	double scalefactor = sizz / m_face->units_per_EM  ;
1176 	double pixelAdjustX = scalefactor * ( typotek::getInstance()->getDpiX() / 72.0 );
1177 	double pixelAdjustY = scalefactor * ( typotek::getInstance()->getDpiX() / 72.0 );
1178 	double pWidth = lineWidth ;
1179 	const double distance = 20;
1180 	QList<RenderedGlyph> refGlyph = otf->procstring ( spec, set );
1181 // 	qDebug() << "Get line "<<spec;
1182 	delete otf;
1183 	otf = 0;
1184 // 	qDebug() << "Deleted OTF";
1185 	if ( refGlyph.count() == 0 )
1186 	{
1187 		return 0;
1188 	}
1189 	QPointF pen ( origine );
1190 
1191 	if ( m_rasterFreetype )
1192 	{
1193 		QList<QGraphicsPixmapItem*> mayBeRemoved;
1194 		for ( int i=0; i < refGlyph.count(); ++i )
1195 		{
1196 			QGraphicsPixmapItem *glyph = itemFromGindexPix ( refGlyph[i].glyph , sizz );
1197 			if ( !glyph )
1198 				continue;
1199 			// Now, all is in the log!
1200 			if( spec.at(refGlyph[i].log).category() == QChar::Separator_Space )
1201 			{
1202 				mayBeRemoved.clear();
1203 			}
1204 
1205 			if ( m_progression == PROGRESSION_RTL )
1206 			{
1207 				pen.rx() -= refGlyph[i].xadvance * pixelAdjustX;
1208 				pWidth -= refGlyph[i].xadvance * pixelAdjustX ;
1209 				if ( pWidth < distance )
1210 				{
1211 					delete glyph;
1212 
1213 					retValue -= mayBeRemoved.count() - 1;
1214 					foreach(QGraphicsPixmapItem *rm, mayBeRemoved)
1215 					{
1216 						scene->removeItem( rm );
1217 						delete rm;
1218 					}
1219 
1220 					break;
1221 				}
1222 			}
1223 			else if ( m_progression == PROGRESSION_BTT )
1224 			{
1225 				pen.ry() -= refGlyph[i].yadvance * pixelAdjustY;
1226 				pWidth -=  refGlyph[i].yadvance * pixelAdjustY;
1227 				if ( pWidth < distance )
1228 				{
1229 					delete glyph;
1230 
1231 					retValue -= mayBeRemoved.count() - 1;
1232 					foreach(QGraphicsPixmapItem *rm, mayBeRemoved)
1233 					{
1234 						scene->removeItem( rm );
1235 						delete rm;
1236 					}
1237 
1238 					break;
1239 				}
1240 			}
1241 			else if ( m_progression == PROGRESSION_LTR )
1242 			{
1243 				pWidth -= refGlyph[i].xadvance * pixelAdjustX;
1244 				if ( pWidth < distance )
1245 				{
1246 					delete glyph;
1247 
1248 					retValue -= mayBeRemoved.count() - 1;
1249 					foreach(QGraphicsPixmapItem *rm, mayBeRemoved)
1250 					{
1251 						scene->removeItem( rm );
1252 						delete rm;
1253 					}
1254 
1255 					break;
1256 				}
1257 			}
1258 			else if ( m_progression == PROGRESSION_TTB )
1259 			{
1260 				pWidth -=  refGlyph[i].yadvance * pixelAdjustY ;
1261 				if ( pWidth < distance )
1262 				{
1263 					delete glyph;
1264 
1265 					retValue -= mayBeRemoved.count() - 1;
1266 					foreach(QGraphicsPixmapItem *rm, mayBeRemoved)
1267 					{
1268 						scene->removeItem( rm );
1269 						delete rm;
1270 					}
1271 
1272 					break;
1273 				}
1274 			}
1275 
1276 			/*************************************************/
1277 
1278 			mayBeRemoved.append(glyph);
1279 
1280 			if(renderReturnWidth)
1281 				retValue += glyph->data ( GLYPH_DATA_HADVANCE ).toDouble() * scalefactor;
1282 			else
1283 				retValue = refGlyph[i].log;
1284 
1285 			scene->addItem ( glyph );
1286 			glyph->setZValue ( 100.0 );
1287 			glyph->setData ( GLYPH_DATA_GLYPH ,"glyph" );
1288 			glyph->setData ( GLYPH_DATA_FONTNAME , fancyName() );
1289 			glyph->setPos ( pen.x() + ( refGlyph[i].xoffset * pixelAdjustX ) + glyph->data ( GLYPH_DATA_BITMAPLEFT ).toDouble() * scalefactor  ,
1290 			                pen.y() + ( refGlyph[i].yoffset * pixelAdjustY ) - glyph->data ( GLYPH_DATA_BITMAPTOP ).toInt() );
1291 			/*************************************************/
1292 
1293 			if ( m_progression == PROGRESSION_LTR )
1294 				pen.rx() += refGlyph[i].xadvance * pixelAdjustX ;
1295 			else if ( m_progression == PROGRESSION_TTB )
1296 				pen.ry() += refGlyph[i].yadvance * pixelAdjustY ;
1297 		}
1298 	}
1299 	else
1300 	{
1301 		QList<QGraphicsPathItem*> mayBeRemoved;
1302 		for ( int i=0; i < refGlyph.count(); ++i )
1303 		{
1304 			QGraphicsPathItem *glyph = itemFromGindex ( refGlyph[i].glyph , sizz );
1305 			if ( !glyph )
1306 				continue;
1307 			if( spec.at(refGlyph[i].log).category() == QChar::Separator_Space )
1308 			{
1309 				mayBeRemoved.clear();
1310 			}
1311 
1312 			if ( m_progression == PROGRESSION_RTL )
1313 			{
1314 				pen.rx() -= refGlyph[i].xadvance * scalefactor;
1315 				pWidth -= refGlyph[i].xadvance * scalefactor;
1316 				if ( pWidth < distance )
1317 				{
1318 					delete glyph;
1319 
1320 					retValue -= mayBeRemoved.count() - 1;
1321 					foreach(QGraphicsPathItem *rm, mayBeRemoved)
1322 					{
1323 						scene->removeItem( rm );
1324 						delete rm;
1325 					}
1326 
1327 					break;
1328 				}
1329 			}
1330 			else if ( m_progression == PROGRESSION_BTT )
1331 			{
1332 				pen.ry() -= refGlyph[i].yadvance * scalefactor;
1333 				pWidth -=  refGlyph[i].yadvance * scalefactor;
1334 				if ( pWidth < distance )
1335 				{
1336 					delete glyph;
1337 
1338 					retValue -= mayBeRemoved.count() - 1;
1339 					foreach(QGraphicsPathItem *rm, mayBeRemoved)
1340 					{
1341 						scene->removeItem( rm );
1342 						delete rm;
1343 					}
1344 
1345 					break;
1346 				}
1347 			}
1348 			else if ( m_progression == PROGRESSION_LTR )
1349 			{
1350 				pWidth -= refGlyph[i].xadvance * scalefactor;
1351 				if ( pWidth < distance )
1352 				{
1353 					delete glyph;
1354 
1355 					retValue -= mayBeRemoved.count() - 1;
1356 					foreach(QGraphicsPathItem *rm, mayBeRemoved)
1357 					{
1358 						scene->removeItem( rm );
1359 						delete rm;
1360 					}
1361 
1362 					break;
1363 				}
1364 			}
1365 			else if ( m_progression == PROGRESSION_TTB )
1366 			{
1367 				pWidth -=  refGlyph[i].yadvance * scalefactor ;
1368 				if ( pWidth < distance )
1369 				{
1370 					delete glyph;
1371 
1372 					retValue -= mayBeRemoved.count() - 1;
1373 					foreach(QGraphicsPathItem *rm, mayBeRemoved)
1374 					{
1375 						scene->removeItem( rm );
1376 						delete rm;
1377 					}
1378 
1379 					break;
1380 				}
1381 			}
1382 
1383 			/**********************************************/
1384 			mayBeRemoved.append(glyph);
1385 
1386 			if(renderReturnWidth)
1387 				retValue += glyph->data ( GLYPH_DATA_HADVANCE ).toDouble() * scalefactor;
1388 			else
1389 				retValue = refGlyph[i].log;
1390 
1391 			scene->addItem ( glyph );
1392 			glyph->setPen(Qt::NoPen);
1393 			glyph->setPos ( pen.x() + ( refGlyph[i].xoffset * scalefactor ),
1394 			                pen.y() + ( refGlyph[i].yoffset * scalefactor ) );
1395 			glyph->setZValue ( 100.0 );
1396 			glyph->setData ( GLYPH_DATA_GLYPH ,"glyph" );
1397 			glyph->setData ( GLYPH_DATA_FONTNAME , fancyName() );
1398 			/*******************************************/
1399 
1400 			if ( m_progression == PROGRESSION_LTR )
1401 				pen.rx() += refGlyph[i].xadvance * scalefactor;
1402 			if ( m_progression == PROGRESSION_TTB )
1403 				pen.ry() += refGlyph[i].yadvance * scalefactor;
1404 		}
1405 	}
1406 
1407 
1408 	releaseFace();
1409 	return retValue + 1;
1410 }
1411 
1412 /// Shaped line
renderLine(QString script,QGraphicsScene * scene,QString spec,QPointF origine,double lineWidth,double fsize)1413 double FontItem::renderLine ( QString script, QGraphicsScene * scene, QString spec, QPointF origine,double lineWidth, double fsize)
1414 {
1415 	qDebug()<<"Shaped("<< spec <<")";
1416 	double retValue(0.0);
1417 	if ( spec.isEmpty() )
1418 		return 0;
1419 	if ( !m_isOpenType )
1420 		return 0;
1421 	ensureFace();
1422 
1423 	otf = new FMOtf ( m_face, 0x10000 );
1424 	if ( !otf )
1425 		return 0;
1426 
1427 	FMShaperFactory *shaperfactory = 0;
1428 	//	switch(m_shaperType)
1429 	//	{
1430 	//		case FMShaperFactory::FONTMATRIX : shaperfactory = new FMShaperFactory(otf,script, FMShaperFactory::FONTMATRIX );
1431 	//		break;
1432 	//		case FMShaperFactory::HARFBUZZ : shaperfactory = new FMShaperFactory(otf,script, FMShaperFactory::HARFBUZZ );
1433 	//		break;
1434 	//		case FMShaperFactory::ICU : shaperfactory = new FMShaperFactory(otf,script, FMShaperFactory::ICU );
1435 	//		break;
1436 	//		case FMShaperFactory::M17N : shaperfactory = new FMShaperFactory(otf,script, FMShaperFactory::M17N );
1437 	//		break;
1438 	//		case FMShaperFactory::PANGO : shaperfactory = new FMShaperFactory(otf,script, FMShaperFactory::PANGO );
1439 	//		break;
1440 	//		case FMShaperFactory::OMEGA : shaperfactory = new FMShaperFactory(otf,script, FMShaperFactory::OMEGA);
1441 	//		break;
1442 	//		default : shaperfactory = new FMShaperFactory(otf,script, FMShaperFactory::FONTMATRIX );
1443 	//	}
1444 
1445 	/// Let's do it only with ICU atm.
1446 	shaperfactory = new FMShaperFactory(otf,script, FMShaperFactory::ICU );
1447 
1448 	GlyphList refGlyph ( shaperfactory->doShape( spec ) );
1449 	delete shaperfactory;
1450 
1451 	double sizz = fsize;
1452 	double scalefactor = sizz / m_face->units_per_EM  ;
1453 	double pixelAdjustX = scalefactor * ( typotek::getInstance()->getDpiX() / 72.0 );
1454 	double pixelAdjustY = scalefactor * ( typotek::getInstance()->getDpiX() / 72.0 );
1455 	double pWidth = lineWidth ;
1456 	const double distance = 20;
1457 
1458 
1459 // 	qDebug() << "Get line "<<spec;
1460 	delete otf;
1461 	otf = 0;
1462 // 	qDebug() << "Deleted OTF";
1463 	if ( refGlyph.count() == 0 )
1464 	{
1465 		return 0;
1466 	}
1467 	QPointF pen ( origine );
1468 
1469 	if ( m_rasterFreetype )
1470 	{
1471 		QList<QGraphicsPixmapItem*> mayBeRemoved;
1472 		for ( int i=0; i < refGlyph.count(); ++i )
1473 		{
1474 			QGraphicsPixmapItem *glyph = itemFromGindexPix ( refGlyph[i].glyph , sizz );
1475 			if ( !glyph )
1476 				continue;
1477 			if( spec.at(refGlyph[i].log).category() == QChar::Separator_Space )
1478 			{
1479 				mayBeRemoved.clear();
1480 			}
1481 
1482 			if ( m_progression == PROGRESSION_RTL )
1483 			{
1484 				pen.rx() -= refGlyph[i].xadvance * pixelAdjustX;
1485 				pWidth -= refGlyph[i].xadvance * pixelAdjustX ;
1486 				if ( pWidth < distance )
1487 				{
1488 					delete glyph;
1489 
1490 					retValue -= mayBeRemoved.count() - 1;
1491 					foreach(QGraphicsPixmapItem *rm, mayBeRemoved)
1492 					{
1493 						scene->removeItem( rm );
1494 						delete rm;
1495 					}
1496 
1497 					break;
1498 				}
1499 			}
1500 			else if ( m_progression == PROGRESSION_BTT )
1501 			{
1502 				pen.ry() -= refGlyph[i].yadvance * pixelAdjustY;
1503 				pWidth -=  refGlyph[i].yadvance * pixelAdjustY;
1504 				if ( pWidth < distance )
1505 				{
1506 					delete glyph;
1507 
1508 					retValue -= mayBeRemoved.count() - 1;
1509 					foreach(QGraphicsPixmapItem *rm, mayBeRemoved)
1510 					{
1511 						scene->removeItem( rm );
1512 						delete rm;
1513 					}
1514 
1515 					break;
1516 				}
1517 			}
1518 			else if ( m_progression == PROGRESSION_LTR )
1519 			{
1520 				pWidth -= refGlyph[i].xadvance * pixelAdjustX;
1521 				if ( pWidth < distance )
1522 				{
1523 					delete glyph;
1524 
1525 					retValue -= mayBeRemoved.count() - 1;
1526 					foreach(QGraphicsPixmapItem *rm, mayBeRemoved)
1527 					{
1528 						scene->removeItem( rm );
1529 						delete rm;
1530 					}
1531 
1532 					break;
1533 				}
1534 			}
1535 			else if ( m_progression == PROGRESSION_TTB )
1536 			{
1537 				pWidth -=  refGlyph[i].yadvance * pixelAdjustY ;
1538 				if ( pWidth < distance )
1539 				{
1540 					delete glyph;
1541 
1542 					retValue -= mayBeRemoved.count() - 1;
1543 					foreach(QGraphicsPixmapItem *rm, mayBeRemoved)
1544 					{
1545 						scene->removeItem( rm );
1546 						delete rm;
1547 					}
1548 
1549 					break;
1550 				}
1551 			}
1552 
1553 			/*************************************************/
1554 
1555 			mayBeRemoved.append(glyph);
1556 
1557 			if(renderReturnWidth)
1558 				retValue += glyph->data ( GLYPH_DATA_HADVANCE ).toDouble() * scalefactor;
1559 			else
1560 				retValue = refGlyph[i].log;
1561 
1562 			scene->addItem ( glyph );
1563 			glyph->setZValue ( 100.0 );
1564 			glyph->setData ( GLYPH_DATA_GLYPH ,"glyph" );
1565 			glyph->setData ( GLYPH_DATA_FONTNAME , fancyName() );
1566 			glyph->setPos ( pen.x() + ( refGlyph[i].xoffset * pixelAdjustX ) + glyph->data ( GLYPH_DATA_BITMAPLEFT ).toDouble() * scalefactor  ,
1567 			                pen.y() - ( refGlyph[i].yoffset * pixelAdjustY ) - glyph->data ( GLYPH_DATA_BITMAPTOP ).toInt() );
1568 			/*************************************************/
1569 
1570 			if ( m_progression == PROGRESSION_LTR )
1571 				pen.rx() += refGlyph[i].xadvance * pixelAdjustX ;
1572 			else if ( m_progression == PROGRESSION_TTB )
1573 				pen.ry() += refGlyph[i].yadvance * pixelAdjustY ;
1574 		}
1575 	}
1576 	else
1577 	{
1578 		QList<QGraphicsPathItem*> mayBeRemoved;
1579 		for ( int i=0; i < refGlyph.count(); ++i )
1580 		{
1581 			QGraphicsPathItem *glyph = itemFromGindex ( refGlyph[i].glyph , sizz );
1582 			if ( !glyph )
1583 				continue;
1584 			if( spec.at(refGlyph[i].log).category() == QChar::Separator_Space )
1585 			{
1586 				mayBeRemoved.clear();
1587 			}
1588 
1589 			if ( m_progression == PROGRESSION_RTL )
1590 			{
1591 				pen.rx() -= refGlyph[i].xadvance * scalefactor;
1592 				pWidth -= refGlyph[i].xadvance * scalefactor;
1593 				if ( pWidth < distance )
1594 				{
1595 					delete glyph;
1596 
1597 					retValue -= mayBeRemoved.count() - 1;
1598 					foreach(QGraphicsPathItem *rm, mayBeRemoved)
1599 					{
1600 						scene->removeItem( rm );
1601 						delete rm;
1602 					}
1603 
1604 					break;
1605 				}
1606 			}
1607 			else if ( m_progression == PROGRESSION_BTT )
1608 			{
1609 				pen.ry() -= refGlyph[i].yadvance * scalefactor;
1610 				pWidth -=  refGlyph[i].yadvance * scalefactor;
1611 				if ( pWidth < distance )
1612 				{
1613 					delete glyph;
1614 
1615 					retValue -= mayBeRemoved.count() - 1;
1616 					foreach(QGraphicsPathItem *rm, mayBeRemoved)
1617 					{
1618 						scene->removeItem( rm );
1619 						delete rm;
1620 					}
1621 
1622 					break;
1623 				}
1624 			}
1625 			else if ( m_progression == PROGRESSION_LTR )
1626 			{
1627 				pWidth -= refGlyph[i].xadvance * scalefactor;
1628 				if ( pWidth < distance )
1629 				{
1630 					delete glyph;
1631 
1632 					retValue -= mayBeRemoved.count() - 1;
1633 					foreach(QGraphicsPathItem *rm, mayBeRemoved)
1634 					{
1635 						scene->removeItem( rm );
1636 						delete rm;
1637 					}
1638 
1639 					break;
1640 				}
1641 			}
1642 			else if ( m_progression == PROGRESSION_TTB )
1643 			{
1644 				pWidth -=  refGlyph[i].yadvance * scalefactor ;
1645 				if ( pWidth < distance )
1646 				{
1647 					delete glyph;
1648 
1649 					retValue -= mayBeRemoved.count() - 1;
1650 					foreach(QGraphicsPathItem *rm, mayBeRemoved)
1651 					{
1652 						scene->removeItem( rm );
1653 						delete rm;
1654 					}
1655 
1656 					break;
1657 				}
1658 			}
1659 
1660 			/**********************************************/
1661 			mayBeRemoved.append(glyph);
1662 
1663 			if(renderReturnWidth)
1664 				retValue += glyph->data ( GLYPH_DATA_HADVANCE ).toDouble() * scalefactor;
1665 			else
1666 				retValue = refGlyph[i].log;
1667 
1668 			scene->addItem ( glyph );
1669 			glyph->setPen(Qt::NoPen);
1670 			glyph->setPos ( pen.x() + ( refGlyph[i].xoffset * scalefactor ),
1671 			                pen.y() - ( refGlyph[i].yoffset * scalefactor ) );
1672 			glyph->setZValue ( 100.0 );
1673 			glyph->setData ( GLYPH_DATA_GLYPH ,"glyph" );
1674 			/*******************************************/
1675 
1676 			if ( m_progression == PROGRESSION_LTR )
1677 				pen.rx() += refGlyph[i].xadvance * scalefactor;
1678 			if ( m_progression == PROGRESSION_TTB )
1679 				pen.ry() += refGlyph[i].yadvance * scalefactor;
1680 		}
1681 	}
1682 
1683 
1684 	releaseFace();
1685 	return retValue + 1;
1686 }
1687 
1688 
deRenderAll()1689 void FontItem::deRenderAll()
1690 {
1691 // 	qDebug() << m_name  <<"::deRenderAll()";
1692 // 	QSet<QGraphicsScene*> collectedScenes;
1693 	for ( int i = 0; i < pixList.count(); ++i )
1694 	{
1695 		if ( pixList[i]->scene() )
1696 		{
1697 // 			collectedScenes.insert ( pixList[i]->scene() );
1698 			pixList[i]->scene()->removeItem ( pixList[i] );
1699 			delete pixList[i];
1700 		}
1701 	}
1702 	pixList.clear();
1703 	for ( int i = 0; i < glyphList.count(); ++i )
1704 	{
1705 		if ( glyphList[i]->scene() )
1706 		{
1707 // 			collectedScenes.insert ( pixList[i]->scene() );
1708 			glyphList[i]->scene()->removeItem ( glyphList[i] );
1709 			delete glyphList[i];
1710 		}
1711 	}
1712 	glyphList.clear();
1713 	for ( int i = 0; i < labList.count(); ++i )
1714 	{
1715 		if ( labList[i]->scene() )
1716 		{
1717 // 			collectedScenes.insert ( pixList[i]->scene() );
1718 			labList[i]->scene()->removeItem ( labList[i] );
1719 			delete labList[i];
1720 		}
1721 	}
1722 	labList.clear();
1723 	for ( int i = 0; i < selList.count(); ++i )
1724 	{
1725 		if ( selList[i]->scene() )
1726 		{
1727 // 			collectedScenes.insert ( pixList[i]->scene() );
1728 			selList[i]->scene()->removeItem ( selList[i] );
1729 			delete selList[i];
1730 		}
1731 	}
1732 	selList.clear();
1733 	allIsRendered = false;
1734 }
1735 
pixarray(uchar * b,int len)1736 QByteArray FontItem::pixarray ( uchar * b, int len )
1737 {
1738 	uchar *imgdata =  b ;
1739 	QByteArray buffer ( len * 4, 255 );
1740 	QDataStream stream ( &buffer,QIODevice::WriteOnly );
1741 	for ( int i = 0 ; i < len; ++i )
1742 	{
1743 
1744 		stream << ( quint8 ) ~imgdata[i];
1745 		stream << ( quint8 ) ~imgdata[i];
1746 		stream << ( quint8 ) ~imgdata[i];
1747 		stream << ( quint8 ) imgdata[i];
1748 	}
1749 
1750 	return buffer;
1751 }
1752 
1753 
1754 
firstChar()1755 int FontItem::firstChar()
1756 {
1757 	if(!ensureFace())
1758 		return 0;
1759 
1760 	FT_UInt anIndex (1);
1761 	FT_UInt fc ( FT_Get_First_Char ( m_face, &anIndex ));
1762 	releaseFace();
1763 
1764 	return fc;
1765 }
1766 
lastChar()1767 int FontItem::lastChar()
1768 {
1769 	if(!ensureFace())
1770 		return 0;
1771 
1772 	FT_UInt index (1);
1773 	FT_UInt cc =  FT_Get_First_Char ( m_face, &index );
1774 	int lc(0);
1775 	while ( index )
1776 	{
1777 		lc = cc;
1778 		cc = FT_Get_Next_Char ( m_face, cc, &index );
1779 	}
1780 
1781 	releaseFace();
1782 	return lc ;
1783 }
1784 
countChars()1785 int FontItem::countChars()
1786 {
1787 	if(!ensureFace())
1788 		return 0;
1789 
1790 	FT_UInt index (1);
1791 	FT_UInt cc =  FT_Get_First_Char ( m_face, &index );
1792 	int n(0);
1793 	while ( index )
1794 	{
1795 		++n;
1796 		cc = FT_Get_Next_Char ( m_face, cc, &index );
1797 	}
1798 
1799 	releaseFace();
1800 	return n;
1801 }
1802 
nextChar(int from,int offset)1803 int FontItem::nextChar(int from, int offset)
1804 {
1805 	if(!ensureFace())
1806 		return 0;
1807 
1808 	FT_UInt index (1);
1809 	int cc(from);
1810 	for ( int i(0); i < offset; ++i )
1811 	{
1812 		cc = FT_Get_Next_Char ( m_face, cc, &index );
1813 	}
1814 
1815 	releaseFace();
1816 	return cc;
1817 }
1818 
countCoverage(int begin_code,int end_code)1819 int FontItem::countCoverage ( int begin_code, int end_code )
1820 {
1821 	if(!ensureFace())
1822 		return 0;
1823 // 	qDebug()<<"CC B E"<<begin_code<<end_code;
1824 	FT_ULong  charcode = begin_code ;
1825 	FT_UInt   gindex = 0;
1826 	int count = 0;
1827 	if ( begin_code >= 0 )
1828 	{
1829 		for ( ;charcode <= end_code ; ++charcode)
1830 		{
1831 			if( FT_Get_Char_Index ( m_face, charcode))
1832 				++count;
1833 		}
1834 	}
1835 	else
1836 	{
1837 		FT_UInt anIndex = 0;
1838 		count = m_numGlyphs;
1839 		FT_UInt anyChar =  FT_Get_First_Char ( m_face, &anIndex );
1840 		while ( anIndex )
1841 		{
1842 			anyChar =  FT_Get_Next_Char ( m_face,anyChar,&anIndex );
1843 			if ( anIndex )
1844 				--count;
1845 		}
1846 	}
1847 	releaseFace();
1848 	return count;//something weird with freetype which put a valid glyph at the beginning of each lang ??? Or a bug here...
1849 }
1850 
hasCharcode(int cc)1851 bool FontItem::hasCharcode(int cc)
1852 {
1853 	if(!ensureFace())
1854 		return false;
1855 	bool ret(true);
1856 	if( !FT_Get_Char_Index( m_face, cc ) )
1857 	{
1858 		ret = false;
1859 	}
1860 	releaseFace();
1861 	return ret;
1862 }
1863 
hasChars(const QString & s)1864 bool FontItem::hasChars(const QString & s)
1865 {
1866 	if(!ensureFace())
1867 		return false;
1868 	bool ret(true);
1869 
1870 	foreach(QChar c, s)
1871 	{
1872 		if( !FT_Get_Char_Index( m_face, c.unicode() ) )
1873 		{
1874 			ret = false;
1875 			break;
1876 		}
1877 	}
1878 
1879 	releaseFace();
1880 	return ret;
1881 }
1882 
renderAll(QGraphicsScene * scene,int begin_code,int end_code)1883 void FontItem::renderAll ( QGraphicsScene * scene , int begin_code, int end_code )
1884 {
1885 
1886 	ensureFace();
1887 
1888 	FMGlyphsView *allView(0);
1889 	if(scene->views().count() > 0)
1890 		allView = reinterpret_cast<FMGlyphsView*> ( scene->views() [0] );
1891 	else
1892 	{
1893 		releaseFace();
1894 		return;
1895 	}
1896 
1897 	deRenderAll();
1898 	if ( !allView->isVisible() )
1899 	{
1900 		releaseFace();
1901 		return;
1902 	}
1903 
1904 
1905 	adjustGlyphsPerRow ( allView->width() );
1906 	QRectF exposedRect ( allView->visibleSceneRect() );
1907 //        qDebug() << exposedRect;
1908 
1909 	double leftMargin = ( ( exposedRect.width() - ( 100 * m_glyphsPerRow ) ) / 2 ) + 30;
1910 	double aestheticTopMargin = 12;
1911 	QPointF pen ( leftMargin, 50  + aestheticTopMargin );
1912 
1913 	int nl = 0;
1914 
1915 	FT_ULong  charcode;
1916 	FT_UInt   gindex = 1;
1917 	double sizz = 50;
1918 	charcode = begin_code;
1919 	QPen selPen ( Qt::gray );
1920 
1921 	QFont infoFont ( typotek::getInstance()->getChartInfoFontName() , typotek::getInstance()->getChartInfoFontSize() );
1922 	QBrush selBrush ( QColor ( 255,255,255,0 ) );
1923 	QColor txtColor(60,60,60,255);
1924 	if ( begin_code >= 0 )
1925 	{
1926 		if ( m_isEncoded )
1927 		{
1928 			while ( charcode <= end_code && gindex )
1929 			{
1930 				if ( nl == m_glyphsPerRow )
1931 				{
1932 					nl = 0;
1933 					pen.rx() = leftMargin;
1934 					pen.ry() += 100;
1935 				}
1936 				if ( ( pen.y() + 100 ) < exposedRect.y() || pen.y() - 100 > ( exposedRect.y() + exposedRect.height() ) )
1937 				{
1938 					charcode = FT_Get_Next_Char ( m_face, charcode, &gindex );
1939 // 					qDebug() << "charcode = "<< charcode <<" ; gindex = "<< gindex;
1940 					pen.rx() += 100;
1941 					++nl;
1942 
1943 					continue;
1944 				}
1945 
1946 				QGraphicsPathItem *pitem = itemFromChar ( charcode , sizz );
1947 				if ( pitem )
1948 				{
1949 					uint ucharcode = charcode;
1950 
1951 					scene->addItem ( pitem );
1952 					pitem->setPen(Qt::NoPen);
1953 					pitem->setPos ( pen );
1954 					pitem->setData ( 1,"glyph" );
1955 					pitem->setData ( 2,gindex );
1956 					pitem->setData ( 3,ucharcode );
1957 					glyphList.append ( pitem );
1958 
1959 					pitem->setZValue ( 10 );
1960 
1961 					QGraphicsTextItem *tit= scene->addText ( glyphName ( charcode ), infoFont );
1962 					tit->setDefaultTextColor(txtColor);
1963 					tit->setPos ( pen.x()-27,pen.y() + 15 );
1964 					tit->setData ( 1,"label" );
1965 					tit->setData ( 2,gindex );
1966 					tit->setData ( 3,ucharcode );
1967 					labList.append ( tit );
1968 					tit->setZValue ( 1 );
1969 
1970 					QGraphicsTextItem *tit2= scene->addText ( "U+" + QString ( "%1" ).arg ( charcode,4,16,QLatin1Char ( '0' ) )  +" ("+ QString::number ( charcode ) +")"  , infoFont );
1971 					tit2->setDefaultTextColor(txtColor);
1972 					tit2->setPos ( pen.x()-27,pen.y() + 28 );
1973 					tit2->setData ( 1,"label" );
1974 					tit2->setData ( 2,gindex );
1975 					tit2->setData ( 3,ucharcode );
1976 					labList.append ( tit2 );
1977 					tit2->setZValue ( 1 );
1978 
1979 					QGraphicsRectItem *rit = scene->addRect ( pen.x() -30,pen.y() -50,100,100,selPen,selBrush );
1980 					rit->setFlag ( QGraphicsItem::ItemIsSelectable,true );
1981 					rit->setData ( 1,"select" );
1982 					rit->setData ( 2,gindex );
1983 					rit->setData ( 3,ucharcode );
1984 					rit->setZValue ( 100 );
1985 					selList.append ( rit );
1986 
1987 					pen.rx() += 100;
1988 					++nl;
1989 				}
1990 				charcode = FT_Get_Next_Char ( m_face, charcode, &gindex );
1991 			}
1992 		}
1993 		else // Has not Unicode
1994 		{
1995 			// Here are fake charcodes (glyph index)
1996 			while ( charcode <= end_code )
1997 			{
1998 				if ( nl == m_glyphsPerRow )
1999 				{
2000 					nl = 0;
2001 					pen.rx() = leftMargin;
2002 					pen.ry() += 100;
2003 				}
2004 
2005 				if ( ( pen.y() + 100 ) < exposedRect.y() || pen.y() - 100 > ( exposedRect.y() + exposedRect.height() ) )
2006 				{
2007 					++charcode;
2008 					++nl;
2009 
2010 					continue;
2011 				}
2012 
2013 				QGraphicsPathItem *pitem = itemFromGindex ( charcode , sizz );
2014 				if ( pitem )
2015 				{
2016 					scene->addItem ( pitem );
2017 					pitem->setPos ( pen );
2018 					pitem->setData ( 1,"glyph" );
2019 					pitem->setData ( 2,gindex );
2020 					pitem->setData ( 3,0 );
2021 					glyphList.append ( pitem );
2022 					pitem->setZValue ( 10 );
2023 
2024 					QGraphicsTextItem *tit= scene->addText ( QString ( "%1" ).arg ( charcode,4,16,QLatin1Char ( '0' ) ) , infoFont );
2025 					tit->setDefaultTextColor(txtColor);
2026 					tit->setPos ( pen.x(),pen.y() + 15 );
2027 					tit->setData ( 1,"label" );
2028 					tit->setData ( 2,gindex );
2029 					tit->setData ( 3,0 );
2030 					labList.append ( tit );
2031 					tit->setZValue ( 1 );
2032 
2033 
2034 					QGraphicsRectItem *rit = scene->addRect ( pen.x() -30,pen.y() -50,100,100,selPen,selBrush );
2035 					rit->setFlag ( QGraphicsItem::ItemIsSelectable,true );
2036 					rit->setData ( 1,"select" );
2037 					rit->setData ( 2,gindex );
2038 					rit->setData ( 3,0 );
2039 					rit->setZValue ( 100 );
2040 					selList.append ( rit );
2041 
2042 					pen.rx() += 100;
2043 					++nl;
2044 				}
2045 				else
2046 				{
2047 					break;
2048 				}
2049 				++charcode;
2050 			}
2051 		}
2052 	}
2053 	else // beginCode is negative - it means search for out charmap glyphs
2054 	{
2055 		// 1/ what is "out charmap"?
2056 		FT_UInt anIndex = 1;
2057 		QList<bool> notCovered;
2058 		for ( int i=1; i  < m_numGlyphs +1; ++i )
2059 			notCovered << true;
2060 		FT_UInt anyChar =  FT_Get_First_Char ( m_face, &anIndex );
2061 		while ( anIndex )
2062 		{
2063 			anyChar =  FT_Get_Next_Char ( m_face,anyChar,&anIndex );
2064 			if ( anIndex && (anIndex <= m_numGlyphs))
2065 			{
2066 				notCovered[anIndex] = false;
2067 			}
2068 		}
2069 
2070 		// 2/ fill with glyphs
2071 		for ( int i = 1; i < notCovered.count(); ++i )
2072 		{
2073 			if ( !notCovered[i] )
2074 				continue;
2075 			if ( nl == m_glyphsPerRow )
2076 			{
2077 				nl = 0;
2078 				pen.rx() = leftMargin;
2079 				pen.ry() += 100;
2080 			}
2081 
2082 			if ( ( pen.y() + 100 ) < exposedRect.y() || pen.y() - 100 > ( exposedRect.y() + exposedRect.height() ) )
2083 			{
2084 				++nl;
2085 
2086 				continue;
2087 			}
2088 
2089 			QGraphicsPathItem *pitem = itemFromGindex ( i , sizz );
2090 			if ( pitem )
2091 			{
2092 				scene->addItem ( pitem );
2093 				pitem->setPos ( pen );
2094 				pitem->setData ( 1,"glyph" );
2095 				pitem->setData ( 2, i );
2096 				pitem->setData ( 3,0 );
2097 				glyphList.append ( pitem );
2098 				pitem->setZValue ( 10 );
2099 
2100 				QGraphicsTextItem *tit= scene->addText ( QString ( "I+%1" ).arg ( i ), infoFont );
2101 				tit->setDefaultTextColor(txtColor);
2102 				tit->setPos ( pen.x(),pen.y() + 15 );
2103 				tit->setData ( 1,"label" );
2104 				tit->setData ( 2,i );
2105 				tit->setData ( 3,0 );
2106 				labList.append ( tit );
2107 				tit->setZValue ( 1 );
2108 
2109 				QGraphicsTextItem *tit2= scene->addText ( glyphName ( i , false), infoFont );
2110 				tit2->setDefaultTextColor(txtColor);
2111 				tit2->setPos ( pen.x()-27,pen.y() + 30 );
2112 				tit2->setData ( 1,"label" );
2113 				tit2->setData ( 2,i );
2114 				labList.append ( tit2 );
2115 				tit2->setZValue ( 1 );
2116 
2117 				QGraphicsRectItem *rit = scene->addRect ( pen.x() -30,pen.y() -50,100,100,selPen,selBrush );
2118 				rit->setFlag ( QGraphicsItem::ItemIsSelectable,true );
2119 				rit->setData ( 1,"select" );
2120 				rit->setData ( 2,i );
2121 				rit->setData ( 3,0 );
2122 				rit->setZValue ( 100 );
2123 				selList.append ( rit );
2124 
2125 				pen.rx() += 100;
2126 				++nl;
2127 			}
2128 		}
2129 	}
2130 
2131 	scene->setSceneRect ( QRectF ( 0,0, m_glyphsPerRow * 100 + 30, pen.y() + 100 ) );
2132 	allIsRendered = true;
2133 	releaseFace();
2134 
2135 //        scene->blockSignals(false);
2136 //	exposedRect = allView->visibleSceneRect();
2137 // 	qDebug() << "ENDOFRENDERALL" <<exposedRect.x() << exposedRect.y() << exposedRect.width() << exposedRect.height();
2138 }
2139 
renderChart(QGraphicsScene * scene,int begin_code,int end_code,double pwidth,double pheight)2140 int FontItem::renderChart ( QGraphicsScene * scene, int begin_code, int end_code ,double pwidth, double pheight )
2141 {
2142 // 	qDebug() <<"FontItem::renderChart ("<< begin_code<<end_code <<")";
2143 
2144 	ensureFace();
2145 	int nl ( 0 );
2146 	int retValue ( 0 );
2147 
2148 	FT_ULong  charcode;
2149 	FT_UInt   gindex = 1;
2150 	double sizz = 50;
2151 	charcode = begin_code;
2152 	adjustGlyphsPerRow ( qRound(pwidth) );
2153 
2154 	double leftMargin = 30 + ( ( pwidth - ( m_glyphsPerRow * 100 ) ) / 2 );
2155 	double aestheticTopMargin = 0;
2156 	QPointF pen ( leftMargin, sizz + aestheticTopMargin );
2157 
2158 
2159 	QPen selPen ( Qt::gray );
2160 	QFont infoFont (  typotek::getInstance()->getChartInfoFontName() , typotek::getInstance()->getChartInfoFontSize()  );
2161 	QBrush selBrush ( QColor ( 255,255,255,0 ) );
2162 
2163 	while ( charcode <= end_code && gindex )
2164 	{
2165 		if ( nl == m_glyphsPerRow )
2166 		{
2167 			nl = 0;
2168 			pen.rx() = leftMargin;
2169 			pen.ry() += 100;
2170 		}
2171 		if ( pen.y() > pheight - 30 )
2172 		{
2173 			releaseFace();
2174 			return  retValue  ;
2175 		}
2176 
2177 
2178 		QGraphicsPathItem *pitem = itemFromChar ( charcode , sizz );
2179 		if ( pitem )
2180 		{
2181 			uint ucharcode = charcode;
2182 
2183 			scene->addItem ( pitem );
2184 			pitem->setPos ( pen );
2185 			pitem->setData ( 1,"glyph" );
2186 			pitem->setData ( 2,gindex );
2187 			pitem->setData ( 3,ucharcode );
2188 // 			glyphList.append ( pitem );
2189 
2190 			pitem->setZValue ( 10 );
2191 
2192 			QGraphicsTextItem *tit= scene->addText ( glyphName ( charcode ), infoFont );
2193 			tit->setPos ( pen.x()-27,pen.y() + 15 );
2194 			tit->setData ( 1,"label" );
2195 			tit->setData ( 2,gindex );
2196 			tit->setData ( 3,ucharcode );
2197 // 			labList.append ( tit );
2198 			tit->setZValue ( 1 );
2199 
2200 			QGraphicsTextItem *tit2= scene->addText ( "U+" + QString ( "%1" ).arg ( charcode,4,16,QLatin1Char ( '0' ) )  +" ("+ QString::number ( charcode ) +")"  , infoFont );
2201 			tit2->setPos ( pen.x()-27,pen.y() + 28 );
2202 			tit2->setData ( 1,"label" );
2203 			tit2->setData ( 2,gindex );
2204 			tit2->setData ( 3,ucharcode );
2205 // 			labList.append ( tit2 );
2206 			tit2->setZValue ( 1 );
2207 
2208 			QGraphicsRectItem *rit = scene->addRect ( pen.x() -30,pen.y() -50,100,100,selPen,selBrush );
2209 			rit->setFlag ( QGraphicsItem::ItemIsSelectable,true );
2210 			rit->setData ( 1,"select" );
2211 			rit->setData ( 2,gindex );
2212 			rit->setData ( 3,ucharcode );
2213 			rit->setZValue ( 100 );
2214 
2215 			pen.rx() += 100;
2216 			++nl;
2217 			++retValue;
2218 		}
2219 		retValue = charcode;
2220 		charcode = FT_Get_Next_Char ( m_face, charcode, &gindex );
2221 	}
2222 	releaseFace();
2223 
2224 	return retValue ;
2225 }
2226 
2227 
glyphName(int codepoint,bool codeIsChar)2228 QString FontItem::glyphName ( int codepoint, bool codeIsChar )
2229 {
2230 	ensureFace();
2231 
2232 	int index(0);
2233 
2234 	if(codeIsChar)
2235 	{
2236 		index = FT_Get_Char_Index ( m_face, codepoint );
2237 		if ( index== 0 )
2238 		{
2239 			return "noname";
2240 		}
2241 	}
2242 	else
2243 		index = codepoint;
2244 
2245 	QByteArray key ( 1001,0 );
2246 	if ( FT_HAS_GLYPH_NAMES ( m_face ) )
2247 	{
2248 		FT_Get_Glyph_Name ( m_face, index, key.data() , 1000 );
2249 		if ( key[0] == char ( 0 ) )
2250 		{
2251 			key = "noname";
2252 		}
2253 	}
2254 	else
2255 	{
2256 		key = "noname";
2257 	}
2258 	return QString ( key );
2259 	releaseFace();
2260 }
2261 
2262 
infoGlyph(int index,int code)2263 QString FontItem::infoGlyph ( int index, int code )
2264 {
2265 	ensureFace();
2266 	QString ret;
2267 	ret += glyphName ( code ) ;
2268 	ret += ", " + QObject::tr ( "codepoint is U+" ) ;
2269 	ret += QString ( "%1" ).arg ( code, 4, 16, QChar ( 0x0030 ) ) ;
2270 	ret += " (int"+ QString::number ( code ) +")";
2271 
2272 	releaseFace();
2273 	return ret;
2274 }
2275 
2276 //deprecated
toElement()2277 QString FontItem::toElement()
2278 {
2279 	QString ret;
2280 	ret = "<fontfile><file>%1</file><tag>%2</tag></fontfile>";
2281 	return ret.arg ( name() ).arg ( tags().join ( "</tag><tag>" ) );
2282 }
2283 
hasCodepointLoaded(int code)2284 QGraphicsPathItem * FontItem::hasCodepointLoaded ( int code )
2285 {
2286 	for ( int i=0;i< glyphList.count();++i )
2287 	{
2288 		if ( glyphList.at ( i )->data ( 3 ).toInt() == code )
2289 			return glyphList.at ( i );
2290 	}
2291 	return 0;
2292 }
2293 
2294 
oneLinePreviewPixmap(QString oneline,QColor fg_color,QColor bg_color,int size_w,int size_f)2295 QPixmap FontItem::oneLinePreviewPixmap ( QString oneline , QColor fg_color, QColor bg_color, int size_w , int size_f )
2296 {
2297 //	if ( m_remote )
2298 //		return fixedPixmap;
2299 //	if ( !theOneLinePreviewPixmap.isNull() )
2300 //	{
2301 //		if ( theOneLinePreviewPixmap.width() == size_w )
2302 //			return theOneLinePreviewPixmap;
2303 //	}
2304 	if ( !ensureFace() )
2305 		return QPixmap();
2306 	QRectF savedRect = theOneLineScene->sceneRect();
2307 
2308 	double theSize = (size_f == 0) ? typotek::getInstance()->getPreviewSize() : size_f;
2309 	double pt2px = typotek::getInstance()->getDpiX() / 72.0;
2310 	double theHeight = theSize * 1.3 * pt2px;
2311 	double theWidth;
2312 	if ( size_w == 0 )
2313 	{
2314 		theWidth = theSize * pt2px * oneline.count() * 1.2;
2315 	}
2316 	else
2317 	{
2318 		theWidth = size_w;
2319 	}
2320 // 	qDebug() << theSize << theHeight << theWidth;
2321 	theOneLineScene->setSceneRect ( 0,0,theWidth, theHeight );
2322 	bool pRTL = typotek::getInstance()->getPreviewRTL();
2323 	QPointF pen ( pRTL ? theWidth - 16 : 16 , theSize *  pt2px );
2324 
2325 	int fsize = qRound(theSize) * 64  ;
2326 	double scalefactor = theSize / m_face->units_per_EM;
2327 
2328 	QPixmap linePixmap ( qRound(theWidth), qRound(theHeight) );
2329 	linePixmap.fill ( bg_color );
2330 	QPainter apainter ( &linePixmap );
2331 
2332 	bool canRender(true);
2333 	for ( int i(0);i < oneline.count() ; ++i )
2334 	{
2335 		if(FT_Get_Char_Index ( m_face, oneline[i].unicode() ) == 0)
2336 		{
2337 			canRender = false;
2338 			break;
2339 		}
2340 	}
2341 	if(canRender)
2342 	{
2343 		for ( int i(0);i < oneline.count() ; ++i )
2344 		{
2345 			int glyphIndex = FT_Get_Char_Index ( m_face, oneline[i].unicode() );
2346 
2347 			FT_Set_Char_Size ( m_face,
2348 					   fsize,
2349 					   0,
2350 					   typotek::getInstance()->getDpiX(),
2351 					   typotek::getInstance()->getDpiY() );
2352 
2353 			if(FT_Load_Glyph ( m_face, glyphIndex, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING ) > 0)
2354 				continue;
2355 			if(FT_Render_Glyph ( m_face->glyph, FT_RENDER_MODE_NORMAL ) > 0)
2356 				continue;
2357 
2358 			if ( pRTL )
2359 				pen.rx() -= qRound ( double(m_glyph->linearHoriAdvance) / 65536 );
2360 			apainter.drawImage ( pen.x() +  m_glyph->bitmap_left , pen.y() - m_glyph->bitmap_top , glyphImage(fg_color) );
2361 			if ( !pRTL )
2362 				pen.rx() += qRound ( double(m_glyph->linearHoriAdvance) / 65536 );
2363 		}
2364 	}
2365 	else
2366 	{
2367 		QString cantRenderString(tr("(%1)", "when doing the font preview, used to denote a font that can not displayed its name"));
2368 		apainter.drawText(pen.x(),pen.y(), cantRenderString.arg(oneline));
2369 	}
2370 
2371 	apainter.end();
2372 	releaseFace();
2373 
2374 	return linePixmap;
2375 //	theOneLinePreviewPixmap = linePixmap;
2376 
2377 
2378 //	if ( !theOneLinePreviewPixmap.isNull() )
2379 //		return theOneLinePreviewPixmap;
2380 
2381 //	theOneLinePreviewPixmap = QPixmap ( qRound(theWidth), qRound(theHeight) );
2382 //	theOneLinePreviewPixmap.fill ( Qt::lightGray );
2383 //	return theOneLinePreviewPixmap;
2384 }
2385 
clearPreview()2386 void FontItem::clearPreview()
2387 {
2388 //	if ( m_remote )
2389 //		return;
2390 //	if ( !theOneLinePreviewPixmap.isNull() )
2391 //		theOneLinePreviewPixmap = QPixmap();
2392 }
2393 
2394 
moreInfo()2395 FontInfoMap FontItem::moreInfo()
2396 {
2397 	FontInfoMap ret;
2398 	if(!ensureFace())
2399 		return ret;
2400 
2401 	if ( testFlag ( m_face->face_flags, FT_FACE_FLAG_SFNT, "1","0" ) == "1" )
2402 	{
2403 		m_isOpenType = true;
2404 	}
2405 
2406 	if(m_isOpenType)
2407 	{
2408 		ret =  moreInfo_sfnt();
2409 	}
2410 	else
2411 	{
2412 		ret =  moreInfo_type1();
2413 	}
2414 	releaseFace();
2415 	return ret;
2416 }
2417 
panose()2418 QString FontItem::panose()
2419 {
2420 	if(!ensureFace())
2421 		return QString("0:0:0:0:0:0:0:0:0:0");
2422 	QStringList pl;
2423 	TT_OS2 *os2 = static_cast<TT_OS2*> ( FT_Get_Sfnt_Table ( m_face, ft_sfnt_os2 ) );
2424 	if ( os2 )
2425 	{
2426 		for ( int bI ( 0 ); bI < 10; ++bI )
2427 		{
2428 			pl << QString::number ( os2->panose[bI] ) ;
2429 		}
2430 	}
2431 	else
2432 	{
2433 		for ( int bI ( 0 ); bI < 10; ++bI )
2434 		{
2435 			pl << QString::number ( 0 ) ;
2436 		}
2437 	}
2438 	releaseFace();
2439 	return pl.join(":");
2440 }
2441 
supportedLangDeclaration()2442 QStringList FontItem::supportedLangDeclaration()
2443 {
2444 	QStringList ret;
2445 	if ( !ensureFace() )
2446 		return ret;
2447 
2448 	TT_OS2 *os2 = static_cast<TT_OS2*> ( FT_Get_Sfnt_Table ( m_face, ft_sfnt_os2 ) );
2449 	if ( os2 )
2450 	{
2451 		QList<FT_ULong> uMaskList;
2452 		uMaskList << os2->ulUnicodeRange1
2453 		<< os2->ulUnicodeRange2
2454 		<< os2->ulUnicodeRange3
2455 		<< os2->ulUnicodeRange4;
2456 		const QMap<int, QPair<int,int> >& uranges(FMEncData::Os2URanges());
2457 		unsigned int mask(1);
2458 		for( int i(0); i < uMaskList.count(); ++i )
2459 		{
2460 			for(int j(0); j < 32; ++j)
2461 			{
2462 				unsigned int set(mask << j);
2463 				if((set & uMaskList[i]) > 0)
2464 				{
2465 					int pos((i * 32) + j);
2466 					if(uranges.contains(pos))
2467 					{
2468 						QString b( FMUniBlocks::block(uranges[pos]) );
2469 						if(!b.isEmpty())
2470 							ret << b;
2471 					}
2472 				}
2473 			}
2474 		}
2475 	}
2476 	releaseFace();
2477 	return ret;
2478 }
2479 
italicAngle()2480 double FontItem::italicAngle()
2481 {
2482 	double ret(0);
2483 	if(!ensureFace())
2484 		return ret;
2485 	if ( testFlag ( m_face->face_flags, FT_FACE_FLAG_SFNT, "1","0" ) == "1" )
2486 	{
2487 		TT_Postscript *post = static_cast<TT_Postscript*> ( FT_Get_Sfnt_Table ( m_face, ft_sfnt_post ) );
2488 		if ( post )
2489 			ret = ( double(post->italicAngle) / double (0x10000) ) ;
2490 	}
2491 	else
2492 	{
2493 		PS_FontInfoRec sinfo ;
2494 		int err = FT_Get_PS_Font_Info ( m_face,&sinfo );
2495 		if ( !err )
2496 			ret = sinfo.italic_angle;
2497 	}
2498 
2499 	releaseFace();
2500 	return ret;
2501 }
2502 
getFsType()2503 FontItem::FsType FontItem::getFsType()
2504 {
2505 	// After some thinking, it appears that it would be a nonsense to not retrieve it from the actual font file.
2506 	FsType fst( NOT_RESTRICTED );
2507 	if(!ensureFace())
2508 		return fst;
2509 
2510 	TT_OS2 *os2 = static_cast<TT_OS2*> ( FT_Get_Sfnt_Table ( m_face, ft_sfnt_os2 ) );
2511 
2512 	if ( os2 )
2513 	{
2514 		fst = FsType(os2->fsType);
2515 	}
2516 
2517 	releaseFace();
2518 	return fst;
2519 }
2520 
table(const QString & tableName)2521 int FontItem::table(const QString & tableName)
2522 {
2523 	if(!ensureFace())
2524 		return 0;
2525 
2526 	if ( !FT_IS_SFNT ( m_face ) )
2527 	{
2528 		releaseFace();
2529 		return 0;
2530 	}
2531 
2532 	uint tag(OTF_name_tag(tableName));
2533 	FT_ULong length( 0 );
2534 	FT_Load_Sfnt_Table ( m_face, tag , 0, NULL, &length );
2535 
2536 	releaseFace();
2537 
2538 	return int(length);
2539 }
2540 
tableData(const QString & tableName)2541 QByteArray FontItem::tableData(const QString & tableName)
2542 {
2543 	QByteArray ret;
2544 	if(!ensureFace())
2545 		return ret;
2546 
2547 	if ( !FT_IS_SFNT ( m_face ) )
2548 	{
2549 		releaseFace();
2550 		return ret;
2551 	}
2552 
2553 	uint tag(OTF_name_tag(tableName));
2554 	FT_ULong length( 0 );
2555 	if ( !FT_Load_Sfnt_Table ( m_face, tag, 0, NULL, &length ) )
2556 	{
2557 		if ( length > 0 )
2558 		{
2559 			ret.resize ( length );
2560 			FT_Load_Sfnt_Table ( m_face, tag, 0, ( FT_Byte * ) ret.data (), &length );
2561 		}
2562 	}
2563 	releaseFace();
2564 	return ret;
2565 }
2566 
2567 
2568 /** reminder
2569 FT_SfntName::name_id
2570 Code  	Meaning
2571 0 	Copyright
2572 1 	Font Family
2573 2 	Font Subfamily
2574 3 	Unique font identifier
2575 4 	Full font name
2576 5 	Version string
2577 6 	Postscript name for the font
2578 7 	Trademark
2579 8 	Manufacturer Name.
2580 9 	Designer
2581 10 	Description
2582 11 	URL Vendor
2583 12 	URL Designer
2584 13 	License Description
2585 14 	License Info URL
2586 15 	Reserved; Set to zero.
2587 16 	Preferred Family
2588 17 	Preferred Subfamily
2589 18 	Compatible Full (Macintosh only)
2590 19 	Sample text
2591 20 	PostScript CID findfont name
2592 */
moreInfo_sfnt()2593 FontInfoMap FontItem::moreInfo_sfnt()
2594 {
2595 	if ( !ensureFace() )
2596 		return FontInfoMap();
2597 
2598 	FontInfoMap moreInfo;
2599 	FT_SfntName tname;
2600 
2601 
2602 	int tname_count = FT_Get_Sfnt_Name_Count ( m_face );
2603 
2604 
2605 	//TODO check encodings and platforms
2606 	for ( int i=0; i < tname_count; ++i )
2607 	{
2608 		FT_Get_Sfnt_Name ( m_face,i,&tname );
2609 		int akey;
2610 		if ( tname.name_id >  255 )
2611 		{
2612 // 			qDebug() << name() <<" has vendor’s specific name id ->" << tname.name_id;
2613 			if ( tname.string_len > 0 )
2614 			{
2615 // 				akey = "VendorKey_" + QString::number ( tname.name_id );
2616 				akey = tname.name_id ;
2617 			}
2618 			else
2619 			{
2620 				continue;
2621 			}
2622 
2623 		}
2624 		else if ( tname.name_id <= FontStrings::Names().count())
2625 		{
2626 			akey =  tname.name_id ;
2627 		}
2628 		else
2629 		{
2630 // 			qDebug() << name() <<" : It seems there are new name IDs in TT spec ("<< tname.name_id <<")!";
2631 			continue;
2632 		}
2633 
2634 		QString avalue;
2635 		///New plan, we’ll put here _user contributed_ statements!
2636 		if ( tname.platform_id ==TT_PLATFORM_MICROSOFT && tname.encoding_id == TT_MS_ID_UNICODE_CS ) // Corresponds to a Microsoft WGL4 charmap, matching Unicode.
2637 		{
2638 			QByteArray array ( ( const char* ) tname.string, tname.string_len );
2639 			QTextCodec *codec = QTextCodec::codecForName ( "UTF-16BE" );
2640 			avalue = codec->toUnicode ( array );
2641 		}
2642 		else if ( tname.platform_id ==TT_PLATFORM_MICROSOFT && tname.encoding_id == TT_MS_ID_SYMBOL_CS ) // Corresponds to Microsoft symbol encoding. PM - don(t understand what it does here? seen in StandardSym.ttf
2643 		{
2644 			avalue = "Here, imagine some nice symbols!";
2645 		}
2646 		else if ( tname.platform_id == TT_PLATFORM_MACINTOSH  && tname.encoding_id == TT_APPLE_ID_DEFAULT ) // Unicode version 1.0
2647 		{
2648 			QByteArray array ( ( const char* ) tname.string, tname.string_len );
2649 			QTextCodec *codec = QTextCodec::codecForName ( "ISO 8859-15" ); // ### give better result than UTF ???
2650 			avalue = codec->toUnicode ( array );
2651 		}
2652 		else if ( tname.platform_id == TT_PLATFORM_APPLE_UNICODE  && tname.encoding_id == TT_APPLE_ID_DEFAULT ) // Unicode version 1.0
2653 		{
2654 			QByteArray array ( ( const char* ) tname.string, tname.string_len );
2655 			QTextCodec *codec = QTextCodec::codecForName ( "ISO 8859-15" ); // ### give better result than UTF ???
2656 			avalue = codec->toUnicode ( array );
2657 		}
2658 		// from  Pajarico, pajarico chez gmail point com
2659 		else if ( tname.platform_id == TT_PLATFORM_APPLE_UNICODE  && tname.encoding_id == TT_APPLE_ID_UNICODE_2_0 )
2660 		{
2661 			QByteArray array ( ( const char* ) tname.string, tname.string_len );
2662 			QTextCodec *codec = QTextCodec::codecForName ( "UTF-16" );
2663 			avalue = codec->toUnicode ( array );
2664 		}
2665 		else if ( tname.platform_id == TT_PLATFORM_MACINTOSH   /*&& tname.encoding_id == TT_MAC_ID_TRADITIONAL_CHINESE*/ )
2666 		{
2667 			QByteArray array ( ( const char* ) tname.string, tname.string_len );
2668 			QTextCodec *codec = QTextCodec::codecForName ( "Apple Roman" );
2669 			avalue = codec->toUnicode ( array );
2670 		}
2671 		else
2672 		{
2673 			avalue = "Unexpected platform - encoding pair ("
2674 			         + QString::number ( tname.platform_id )
2675 			         + "," + QString::number ( tname.encoding_id )
2676 			         + ")\nPlease contact Fontmatrix team.\nRun Fontmatrix in console to see more info.\nPlease, if possible, provide a font file to test.";
2677 
2678 			qDebug() << m_name
2679 			<< "platform_id("
2680 			<< tname.platform_id
2681 			<<") - encoding_id("
2682 			<< tname.encoding_id
2683 			<<") - "
2684 			<< QString::number ( tname.language_id )
2685 					<< FMEncData::LangIdMap()[tname.language_id];
2686 		}
2687 
2688 
2689 		if ( !avalue.isEmpty() )
2690 		{
2691 			moreInfo[tname.language_id][akey] = avalue;
2692 		}
2693 	}
2694 
2695 	// Is there an OS/2 table?
2696 // 	TT_OS2 *os2 = static_cast<TT_OS2*> ( FT_Get_Sfnt_Table ( m_face, ft_sfnt_os2 ) );
2697 // 	if ( os2 /* and  wantAutoTag*/ )
2698 // 	{
2699 // 		// PANOSE
2700 // 		QStringList pl;
2701 // 		for ( int bI ( 0 ); bI < 10; ++bI )
2702 // 		{
2703 //
2704 // 			pl << QString::number ( os2->panose[bI] ) ;
2705 // 		}
2706 //
2707 // 		moreInfo[0][FMFontDb::Panose] = pl.join(":");
2708 // 		// FSTYPE (embedding status)
2709 // 		if(!os2->fsType)
2710 // 			m_OSFsType = NOT_RESTRICTED;
2711 // 		else
2712 // 		{
2713 // 			if(os2->fsType & RESTRICTED)
2714 // 				m_OSFsType |= RESTRICTED;
2715 // 			if(os2->fsType & PREVIEW_PRINT)
2716 // 				m_OSFsType |= PREVIEW_PRINT;
2717 // 			if(os2->fsType &  EDIT_EMBED)
2718 // 				m_OSFsType |= EDIT_EMBED;
2719 // 			if(os2->fsType & NOSUBSET)
2720 // 				m_OSFsType |= NOSUBSET;
2721 // 			if(os2->fsType & BITMAP_ONLY)
2722 // 				m_OSFsType |=  BITMAP_ONLY;
2723 // 		}
2724 //
2725 // 	}
2726 
2727 	releaseFace();
2728 	return moreInfo;
2729 }
2730 
getAlternateFamilyName()2731 QString FontItem::getAlternateFamilyName()
2732 {
2733 	if ( !ensureFace() )
2734 		return QString();
2735 
2736 	FT_SfntName tname;
2737 	int tname_count = FT_Get_Sfnt_Name_Count ( m_face );
2738 	for ( int i=0; i < tname_count; ++i )
2739 	{
2740 		FT_Get_Sfnt_Name ( m_face , i , &tname );
2741 		if ( tname.name_id == 1 && tname.language_id == 0 )
2742 		{
2743 			return QString ( QByteArray ( ( const char* ) tname.string, tname.string_len ) );
2744 		}
2745 
2746 	}
2747 
2748 	releaseFace();
2749 	return QString();
2750 }
2751 
getAlternateVariantName()2752 QString FontItem::getAlternateVariantName()
2753 {
2754 	if ( !ensureFace() )
2755 		return QString();
2756 
2757 	FT_SfntName tname;
2758 	int tname_count = FT_Get_Sfnt_Name_Count ( m_face );
2759 	for ( int i=0; i < tname_count; ++i )
2760 	{
2761 		FT_Get_Sfnt_Name ( m_face , i , &tname );
2762 		if ( tname.name_id == 2 && tname.language_id == 0 )
2763 		{
2764 			return QString ( QByteArray ( ( const char* ) tname.string, tname.string_len ) );
2765 		}
2766 
2767 	}
2768 
2769 	releaseFace();
2770 	return QString();
2771 }
2772 
2773 
moreInfo_type1()2774 FontInfoMap FontItem::moreInfo_type1()
2775 {
2776 	if ( !ensureFace() )
2777 		return FontInfoMap();
2778 
2779 	FontInfoMap moreInfo;
2780 	PS_FontInfoRec sinfo ;
2781 	int err = FT_Get_PS_Font_Info ( m_face,&sinfo );
2782 	if ( err )
2783 	{
2784 		qDebug() <<"FT_Get_PS_Font_Info("<< m_name <<")"<<" failed :" << err;
2785 		return FontInfoMap();
2786 	}
2787 
2788 	moreInfo[0][1] = sinfo.family_name;
2789 	moreInfo[0][2] = sinfo.weight;
2790 	moreInfo[0][4] = sinfo.full_name;
2791 	moreInfo[0][5] = sinfo.version;
2792 	moreInfo[0][10] = sinfo.notice;
2793 
2794 	releaseFace();
2795 	return moreInfo;
2796 }
2797 
tags() const2798 QStringList FontItem::tags()const
2799 {
2800 	return FMFontDb::DB()->getValue(m_path, FMFontDb::Tags).toStringList();
2801 }
2802 
addTag(const QString & t)2803 void FontItem::addTag(const QString & t)
2804 {
2805 	FMFontDb::DB()->addTag(m_path, t);
2806 }
2807 
setTags(QStringList l)2808 void FontItem::setTags ( QStringList l )
2809 {
2810 
2811 	FMFontDb::DB()->setTags(m_path, l);
2812 }
2813 
2814 
2815 /// When glyphsView is resized we wantto adjust the number of columns
adjustGlyphsPerRow(int width)2816 void FontItem::adjustGlyphsPerRow ( int width )
2817 {
2818 	m_glyphsPerRow = 1;
2819 	int extraAdjust = 30;
2820 	for ( int i = 1; i < 30 ; ++i )
2821 	{
2822 		if ( ( i*100 ) +extraAdjust > width )
2823 			return;
2824 		else
2825 			m_glyphsPerRow = i;
2826 	}
2827 }
2828 
isActivated() const2829 bool FontItem::isActivated() const
2830 {
2831 // 	if ( FMFontDb::DB()->getValue(m_path,FMFontDb::Activation ).toInt() > 0 )
2832 // 		return true;
2833 //
2834 	return m_active;
2835 }
2836 
setActivated(bool act)2837 void FontItem::setActivated ( bool act )
2838 {
2839 	m_active = act;
2840 	if ( act )
2841 	{
2842 		FMFontDb::DB()->setValue(m_path, FMFontDb::Activation , 1);
2843 	}
2844 	else
2845 	{
2846 		FMFontDb::DB()->setValue(m_path, FMFontDb::Activation , 0);
2847 	}
2848 }
2849 
2850 
2851 
takeOTFInstance()2852 FMOtf * FontItem::takeOTFInstance()
2853 {
2854 	ensureFace();
2855 	if ( m_isOpenType )
2856 		otf = new FMOtf ( m_face );
2857 	return otf;
2858 
2859 	// It is a case where we don’t release face, thr caller have to call releaseOTFInstance;
2860 }
2861 
releaseOTFInstance(FMOtf * rotf)2862 void FontItem::releaseOTFInstance ( FMOtf * rotf )
2863 {
2864 	if ( rotf == otf )
2865 	{
2866 		delete otf;
2867 		otf = 0;
2868 	}
2869 	releaseFace();
2870 }
2871 
features()2872 QStringList FontItem::features()
2873 {
2874 	QStringList ret;
2875 	if(!takeOTFInstance())
2876 	{
2877 		releaseOTFInstance(otf);
2878 		return ret;
2879 	}
2880 
2881 	foreach ( QString table, otf->get_tables() )
2882 	{
2883 		otf->set_table ( table );
2884 		foreach ( QString script, otf->get_scripts() )
2885 		{
2886 			otf->set_script ( script );
2887 			foreach ( QString lang, otf->get_langs() )
2888 			{
2889 				otf->set_lang ( lang );
2890 				foreach ( QString feature, otf->get_features() )
2891 				{
2892 					if(ret.contains(feature))
2893 						ret << feature;
2894 				}
2895 			}
2896 		}
2897 	}
2898 	releaseOTFInstance(otf);
2899 	return ret;
2900 }
2901 
showFancyGlyph(QGraphicsView * view,int charcode,bool charcodeIsAGlyphIndex)2902 int FontItem::showFancyGlyph ( QGraphicsView *view, int charcode , bool charcodeIsAGlyphIndex )
2903 {
2904 	ensureFace();
2905 
2906 	int ref ( fancyGlyphs.count() );
2907 	QRect allRect ( view->rect() );
2908 	QRect targetRect ( view->mapToScene ( allRect.topLeft() ).toPoint(),  view->mapToScene ( allRect.bottomRight() ).toPoint() ) ;
2909 // 	qDebug() <<  allRect.topLeft() << view->mapToScene ( allRect.topLeft() );
2910 
2911 	// We’ll try to have a square subRect that fit in view ;-)
2912 	int squareSideUnit = qMin ( allRect.width() * 0.1,  allRect.height() * 0.1) ;
2913 	int squareSide = 8 * squareSideUnit;
2914 	int squareXOffset = ( allRect.width() - squareSide ) / 2;
2915 	int squareYOffset = ( allRect.height() - squareSide ) / 2;
2916 	QRect subRect ( QPoint ( squareXOffset , squareYOffset ),
2917 	                QSize ( squareSide, squareSide ) );
2918 	QPixmap pix ( allRect.width(), allRect.height() );
2919 	pix.fill ( QColor ( 30,0,0,120 ) );
2920 	QPainter painter ( &pix );
2921 	painter.setRenderHint(QPainter::Antialiasing, true);
2922 	painter.setBrush ( Qt::white );
2923 	painter.setPen ( QPen ( QBrush( QColor ( 0,0,0,255 ) ), 3/*, Qt::DashLine*/ ) );
2924 	painter.drawRoundRect ( subRect,5,5 );
2925 	painter.setPen ( QPen ( QColor ( 0,0,255,120 ) ) );
2926 
2927 	ft_error = FT_Set_Pixel_Sizes ( m_face, 0, qRound(subRect.height() * 0.8) );
2928 	if ( ft_error )
2929 	{
2930 		return -1;
2931 	}
2932 	if ( !charcodeIsAGlyphIndex )
2933 		ft_error = FT_Load_Char ( m_face, charcode  , FT_LOAD_RENDER );
2934 	else
2935 		ft_error = FT_Load_Glyph ( m_face, charcode  , FT_LOAD_RENDER );
2936 	if ( ft_error )
2937 	{
2938 		return -1;
2939 	}
2940 
2941 	QVector<QRgb> palette;
2942 	for ( int i = 0; i < m_face->glyph->bitmap.num_grays; ++i )
2943 	{
2944 		palette << qRgb ( 255 - i,255 - i,255 - i );
2945 	}
2946 	QImage img ( m_face->glyph->bitmap.buffer,
2947 	             m_face->glyph->bitmap.width,
2948 	             m_face->glyph->bitmap.rows,
2949 	             m_face->glyph->bitmap.pitch,
2950 	             QImage::Format_Indexed8 );
2951 	img.setColorTable ( palette );
2952 
2953 	double scaledBy = 1.0;
2954 	if ( img.width() > subRect.width() )
2955 	{
2956 		scaledBy = ( double ) subRect.width() / ( double ) img.width() * 0.8;
2957 // 		qDebug() <<"scaledBy = " << scaledBy ;
2958 		img = img.scaledToWidth ( qRound(subRect.width() * 0.8 ),Qt::SmoothTransformation );
2959 
2960 	}
2961 
2962 	QPoint gPos ( subRect.topLeft() );
2963 	gPos.rx() += ( subRect.width() - img.width() ) / 2;
2964 	gPos.ry() += ( subRect.height() - img.height() ) /2;
2965 	painter.drawImage ( gPos, img );
2966 
2967 
2968 	/// Draw metrics
2969 	int iAngle(italicAngle());
2970 	QPoint pPos ( gPos );
2971 	pPos.rx() -= qRound(m_face->glyph->bitmap_left * scaledBy);
2972 	pPos.ry() += qRound(m_face->glyph->bitmap_top * scaledBy);
2973 	double aF(tan((3.14/180.0) * iAngle));
2974 	double asc(subRect.top() - pPos.y());
2975 	double desc(pPos.y() - subRect.bottom());
2976 	//left
2977 	painter.drawLine ( pPos.x() + (asc * aF), subRect.top(),
2978 			   pPos.x() - (desc * aF), subRect.bottom() );
2979 	//right
2980 	painter.drawLine (  qRound(pPos.x() + m_face->glyph->metrics.horiAdvance / 64 * scaledBy ) + (asc * aF), subRect.top(),
2981 			    qRound( pPos.x() + m_face->glyph->metrics.horiAdvance / 64 * scaledBy) - (desc * aF), subRect.bottom() );
2982 	//baseline
2983 	painter.drawLine ( subRect.left() , pPos.y() ,
2984 			   subRect.right(),  pPos.y() );
2985 
2986 	painter.end();
2987 
2988 	QGraphicsPixmapItem *fancyGlyph = new  QGraphicsPixmapItem;
2989 	fancyGlyph->setPixmap ( pix );
2990 	fancyGlyph->setZValue ( 10000 );
2991 	fancyGlyph->setPos ( targetRect.topLeft() );
2992 	view->scene()->addItem ( fancyGlyph );
2993 	fancyGlyphs[ref] =  fancyGlyph ;
2994 
2995 
2996 	QGraphicsTextItem *textIt = new QGraphicsTextItem;
2997 	textIt->setTextWidth ( allRect.width() );
2998 
2999 	QString itemNameStyle ( "background-color:#000;color:#fff;font-weight:bold;font-size:13pt;padding:0 3px;" );
3000 	QString itemValueStyle ( "background-color:#fff;color:#000;font-size:9pt;padding:0 3px;" );
3001 
3002 	if ( charcodeIsAGlyphIndex )
3003 	{
3004 		QString html(QString("<span style=\"%1\"> %2 </span> <span style=\"%3\"> - Index %4 <span>")
3005 			     .arg(itemNameStyle)
3006 			     .arg(glyphName(charcode))
3007 			     .arg(itemValueStyle)
3008 			     .arg(QString::number ( charcode )));
3009 		textIt->setHtml ( html );
3010 	}
3011 	else
3012 	{
3013 		QString catString;
3014 		catString = FontStrings::UnicodeCategory(QChar::category(static_cast<uint> ( charcode )));
3015 
3016 		QString html(QString("<span style=\"%1\"> %2 </span> <span style=\"%3\"> %4 - U+%5  &#60;&#38;#%6;&#62; <span>")
3017 			     .arg(itemNameStyle)
3018 			     .arg(glyphName(charcode))
3019 			     .arg(itemValueStyle)
3020 			     .arg(catString)
3021 			     .arg(QString("%1").arg(charcode, 4, 16, QChar('0')).toUpper())
3022 			     .arg(charcode));
3023 
3024 		textIt->setHtml ( html );
3025 	}
3026 
3027 // 	qDebug()<< textIt->toHtml();
3028 //	QPointF tPos ( subRect.left() + 18.0 , subRect.bottom() );
3029 	QRectF tRect(textIt->boundingRect());
3030 	QPointF tPos ( -3, targetRect.bottom() - tRect.height() +5);
3031 	textIt->setPos ( tPos );
3032 	textIt->setZValue ( 2000000 );
3033 	textIt->setEnabled ( true );
3034 	textIt->setFlags ( QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable );
3035 	textIt->setData ( 10, "FancyText" );
3036 	view->scene()->addItem ( textIt );
3037 	fancyTexts[ref] = textIt ;
3038 
3039 
3040 	// Alternates
3041 	if ( !charcodeIsAGlyphIndex && m_isOpenType )
3042 	{
3043 		QList<int> alts ( getAlternates ( charcode ) );
3044 		qDebug() << "PALTS"<<alts;
3045 		double altSize ( squareSide / 6 );
3046 		double altXOffset ( subRect.top() + 10 );
3047 		for ( int a ( 0 ); a < alts.count() ; ++a )
3048 		{
3049 			QGraphicsPixmapItem *gpi ( itemFromGindexPix ( alts.at ( a ), altSize ) );
3050 			fancyAlternates[ref] << gpi;
3051 
3052 			QImage altI ( gpi->pixmap().toImage().alphaChannel() );
3053 			QPixmap altP ( altI.width() * 2, altI.height() * 2 );
3054 			altP.fill ( Qt::transparent );
3055 			QPainter altPainter ( &altP );
3056 			altPainter.setRenderHint ( QPainter::Antialiasing,true );
3057 			altPainter.setBrush ( Qt::black );
3058 			altPainter.drawRoundRect ( 5,
3059 			                           5,
3060 			                           altP.width() - 10,
3061 			                           altP.height()  - 10,
3062 			                           20,20 );
3063 			altPainter.drawImage ( qRound(altI.width() / 2.0), qRound(altI.height() / 2.0) , altI );
3064 
3065 			gpi->setPixmap ( altP );
3066 
3067 
3068 			view->scene()->addItem ( gpi );
3069 			gpi->setPos ( view->mapToScene ( subRect.right()  ,altXOffset ) );
3070 			altXOffset += altP.height();
3071 			gpi->setZValue ( 9999999 );
3072 			qDebug() <<gpi->pos() <<gpi->scenePos();
3073 		}
3074 
3075 	}
3076 
3077 	releaseFace();
3078 	return ref;
3079 
3080 }
3081 
hideFancyGlyph(int ref)3082 void FontItem::hideFancyGlyph ( int ref )
3083 {
3084 	if ( fancyGlyphs.contains ( ref ) )
3085 	{
3086 		QGraphicsPixmapItem *it = fancyGlyphs.value ( ref );
3087 		it->scene()->removeItem ( it );
3088 		fancyGlyphs.remove ( ref );
3089 		delete it;
3090 
3091 	}
3092 	if ( fancyTexts.contains ( ref ) )
3093 	{
3094 		QGraphicsTextItem *it = fancyTexts.value ( ref );
3095 		it->scene()->removeItem ( it );
3096 		fancyTexts.remove ( ref );
3097 		delete it;
3098 	}
3099 	if ( fancyAlternates.value ( ref ).count() )
3100 	{
3101 		QList<QGraphicsPixmapItem*> pil ( fancyAlternates.value ( ref ) );
3102 		for ( int pidx ( 0 ); pidx < pil.count(); ++pidx )
3103 		{
3104 			QGraphicsPixmapItem *it = pil.at ( pidx ) ;
3105 			it->scene()->removeItem ( it );
3106 			delete it;
3107 		}
3108 		fancyAlternates.remove ( ref );
3109 	}
3110 }
3111 
3112 
isLocal()3113 bool FontItem::isLocal()
3114 {
3115 	QString shem = m_url.scheme();
3116 	if ( shem.isEmpty() || shem == "file" )
3117 		return true;
3118 	return false;
3119 }
3120 
3121 /// We don’t want to download fonts yet. We just want something to fill font tree
fileRemote(QString f,QString v,QString t,QString i,QPixmap p)3122 void FontItem::fileRemote ( QString f , QString v, QString t, QString i, QPixmap p )
3123 {
3124 	m_family = f;
3125 	m_variant = v;
3126 	m_type = t;
3127 // 	m_cacheInfo = i;
3128 //	fixedPixmap = p;
3129 }
3130 
3131 /// the same, but just for speedup startup with a lot of font files
fileLocal(QString f,QString v,QString t,QString p)3132 void FontItem::fileLocal ( QString f, QString v, QString t, QString p )
3133 {
3134 	m_family = f;
3135 	m_variant = v;
3136 	m_type = t;
3137 }
3138 
fileLocal(FontLocalInfo fli)3139 void FontItem::fileLocal ( FontLocalInfo fli )
3140 {
3141 	m_family = fli.family;
3142 	m_variant = fli.variant;
3143 	m_type = fli.type;
3144 // 	m_panose = fli.panose;
3145 // 	moreInfo = fli.info;
3146 // 	if ( !fli.panose.isEmpty() )
3147 // 	{
3148 // 		for ( int bI ( 0 ); bI < 10; ++bI )
3149 // 		{
3150 // 			panoseInfo[ panoseKeys[bI] ] = panoseMap.value ( panoseKeys[bI] ).value ( m_panose.mid ( bI,1 ).toInt() ) ;
3151 //
3152 // 		}
3153 //
3154 // 	}
3155 
3156 }
3157 
3158 
3159 /// Finally, we have to download the font file
getFromNetwork()3160 int FontItem::getFromNetwork()
3161 {
3162 	qDebug() <<"FontItem::getFromNetwork()";
3163 	if ( remoteCached )
3164 		return 1;
3165 	if ( stopperDownload )
3166 		return 2;
3167 	else
3168 		stopperDownload = true;
3169 
3170 	QUrl url ( m_path );
3171 	remoteHerePath = typotek::getInstance()->remoteTmpDir() + QDir::separator() + QFileInfo ( url.path() ).fileName();
3172 
3173 	rFile = new QFile ( remoteHerePath );
3174 	if ( !rFile->open ( QIODevice::WriteOnly ) )
3175 	{
3176 		qDebug() << "Can’t open " << remoteHerePath;
3177 		delete rFile;
3178 // 		return false;
3179 	}
3180 #if 0 // TODO Must be re-implemented
3181 	rHttp = new QHttp ( url.host() );
3182 	qDebug() << "Init progress Dialog";
3183 	rProgressDialog = new QProgressDialog ( typotek::getInstance() );
3184 	rProgressDialog->setWindowTitle ( tr ( "Fontmatrix - Download" ) );
3185 	rProgressDialog->setLabelText ( tr ( "Downloading %1." ).arg ( m_path ) );
3186 	rProgressDialog->show();
3187 	rProgressDialog->raise();
3188 	rProgressDialog->activateWindow();
3189 	qDebug() <<"Progress dialog done";
3190 
3191 	connect ( rHttp,SIGNAL ( dataReadProgress ( int, int ) ),this,SLOT ( slotDowloadProgress ( int,int ) ) );
3192 	connect ( rHttp,SIGNAL ( requestFinished ( int, bool ) ),this,SLOT ( slotDownloadEnd ( int, bool ) ) );
3193 	connect ( rHttp,SIGNAL ( done ( bool ) ),this,SLOT ( slotDownloadDone ( bool ) ) );
3194 	connect ( rHttp,SIGNAL ( stateChanged ( int ) ),this,SLOT ( slotDownloadState ( int ) ) );
3195 
3196 	remoteId = rHttp->get ( url.path() , rFile );
3197 #endif
3198 	return 2;
3199 }
3200 
slotDownloadStart(int id)3201 void FontItem::slotDownloadStart ( int id )
3202 {
3203 // 	rProgressDialog->show();
3204 	if ( id != remoteId )
3205 	{
3206 		qDebug() << "catched a weird request : " << id;
3207 	}
3208 }
3209 
slotDowloadProgress(int done,int total)3210 void FontItem::slotDowloadProgress ( int done, int total )
3211 {
3212 	rProgressDialog->setMaximum ( total );
3213 	rProgressDialog->setValue ( done );
3214 	qDebug() << " [" <<done << "/"<< total<<"]" ;
3215 }
3216 
slotDownloadEnd(int id,bool error)3217 void FontItem::slotDownloadEnd ( int id, bool error )
3218 {
3219 	qDebug() << m_path << "::slotDownloadEnd ["<< id <<"] when remoteCached = "<< remoteCached;
3220 	if ( id != remoteId )
3221 	{
3222 		qDebug() << "WTF this id("<< id <<") comes from nowhere, our is "<< remoteId;
3223 		return;
3224 	}
3225 	if ( remoteCached )
3226 	{
3227 		qDebug() << "Youre a bit late dude.";
3228 		return;
3229 	}
3230 	else
3231 	{
3232 		remoteCached = true;
3233 	}
3234 	rFile->flush();
3235 	rFile->close();
3236 #if 0
3237 	rHttp->close(); // TODO Must be replaced
3238 #endif
3239 
3240 	delete rProgressDialog;
3241 	delete rFile;
3242 
3243 	emit dowloadFinished();
3244 }
3245 
slotDownloadDone(bool error)3246 void FontItem::slotDownloadDone ( bool error )
3247 {
3248 	qDebug() << "slotDownloadDone(" <<error<<")";
3249 }
3250 
slotDownloadState(int state)3251 void FontItem::slotDownloadState ( int state )
3252 {
3253 #if 0 // TODO Must be re-implemented
3254 // 	qDebug() << "slotDownloadState("<<state<<")";
3255 	if ( state == QHttp::Unconnected  && rHttp )
3256 	{
3257 		qDebug() << "slotDownloadState( QHttp::Unconnected )";
3258 		delete rHttp;
3259 		rHttp = 0;
3260 	}
3261 #endif
3262 }
3263 
3264 
trimSpacesIndex()3265 void FontItem::trimSpacesIndex()
3266 {
3267 	if ( !spaceIndex.isEmpty() )
3268 		return;
3269 	if ( !ensureFace() )
3270 		return;
3271 
3272 	int gIndex ( 0 );
3273 	for ( int i ( 0 ); i < legitimateNonPathChars.count(); ++i )
3274 	{
3275 		gIndex =   FT_Get_Char_Index ( m_face , legitimateNonPathChars[i] );
3276 		if ( gIndex )
3277 		{
3278 // 			qDebug()<<"Space : " << legitimateNonPathChars[i] << " is : "<<gIndex;
3279 			spaceIndex << gIndex;
3280 		}
3281 	}
3282 
3283 	releaseFace();
3284 }
3285 
activationName()3286 QString FontItem::activationName()
3287 {
3288 	if ( m_remote /*|| m_lock*/ )
3289 		return QString();
3290 
3291 	QFileInfo fi ( m_path );
3292 	QString prefix ( "%1-" );
3293 	return  prefix.arg ( fi.size() ) + fi.fileName();
3294 }
3295 
activationAFMName()3296 QString FontItem::activationAFMName()
3297 {
3298 	if ( m_remote /*|| m_lock*/ )
3299 		return QString();
3300 	if ( m_afm.isEmpty() )
3301 		return QString();
3302 
3303 	QFileInfo afi ( m_afm );
3304 	QFileInfo fi ( m_path );
3305 	QString prefix ( "%1-" );
3306 	return  prefix.arg ( fi.size() ) + afi.fileName();
3307 }
3308 
getAlternates(int ccode)3309 QList< int > FontItem::getAlternates ( int ccode )
3310 {
3311 	QList<int> ret;
3312 	if ( !ensureFace() )
3313 		return ret;
3314 	if ( !otf && m_isOpenType )
3315 	{
3316 		otf = new FMOtf ( m_face );
3317 		if ( !otf )
3318 			return ret;
3319 	}
3320 
3321 	int glyphIndex ( FT_Get_Char_Index ( m_face, ccode ) );
3322 	QList<OTFSet> setList;
3323 	setList.clear();
3324 
3325 	otf->set_table ( "GSUB" );
3326 	foreach ( QString script, otf->get_scripts() )
3327 	{
3328 		otf->set_script ( script );
3329 		foreach ( QString lang, otf->get_langs() )
3330 		{
3331 			otf->set_lang ( lang );
3332 			QStringList fl ( otf->get_features() );
3333 			if ( fl.contains ( "aalt" ) )
3334 			{
3335 				OTFSet set;
3336 				set.script = script;
3337 				set.lang = lang;
3338 				set.gpos_features.clear();
3339 				set.gsub_features = QStringList ( "aalt" );
3340 				setList << set;
3341 				qDebug() << "AALT"<<script<< lang;
3342 			}
3343 		}
3344 	}
3345 
3346 	QString spec;
3347 	spec = QChar ( ccode );
3348 
3349 	foreach ( OTFSet set, setList )
3350 	{
3351 		QList<RenderedGlyph> rendered ( otf->procstring ( spec, set ) );
3352 		if(rendered.isEmpty())
3353 			continue;
3354 		if ( rendered.at ( 0 ).glyph != glyphIndex )
3355 		{
3356 			if ( !ret.contains ( rendered.at ( 0 ).glyph ) )
3357 				ret << rendered.at ( 0 ).glyph;
3358 		}
3359 		if ( !otf->altGlyphs.isEmpty() )
3360 		{
3361 			QList<int> l ( otf->altGlyphs );
3362 			foreach ( int g, l )
3363 			{
3364 				if ( !ret.contains ( g ) && g != glyphIndex )
3365 					ret << g;
3366 			}
3367 		}
3368 	}
3369 
3370 	delete otf;
3371 	otf = 0;
3372 
3373 	releaseFace();
3374 	return ret;
3375 }
3376 
glyphImage(QColor color)3377 QImage FontItem::glyphImage(QColor color)
3378 {
3379 	QImage img ( m_face->glyph->bitmap.width, m_face->glyph->bitmap.rows, QImage::Format_Indexed8);
3380 // 	QImage img ( m_face->glyph->bitmap.buffer,
3381 // 	             m_face->glyph->bitmap.width,
3382 // 	             m_face->glyph->bitmap.rows,
3383 // 	             m_face->glyph->bitmap.pitch,
3384 // 	             QImage::Format_Indexed8 );
3385 
3386 // 	qDebug()<<"GSlot"<< m_face->glyph->bitmap.buffer
3387 // 			<< m_face->glyph->bitmap.width
3388 // 			<< m_face->glyph->bitmap.rows
3389 // 			<< m_face->glyph->bitmap.pitch ;
3390 
3391 	if ( (m_face->glyph->bitmap.num_grays != 256)
3392 		     || (color != QColor(Qt::black))  )
3393 	{
3394 		QVector<QRgb> palette;
3395 		palette.clear();
3396 		int r(color.red());
3397 		int g(color.green());
3398 		int b(color.blue());
3399 		for ( int aa = 0; aa < m_face->glyph->bitmap.num_grays; ++aa )
3400 		{
3401 			palette << qRgba ( r,g,b, aa );
3402 		}
3403 		img.setColorTable ( palette );
3404 	}
3405 	else
3406 	{
3407 		img.setColorTable ( gray256Palette );
3408 	}
3409 
3410 
3411 	unsigned char * cursor(m_face->glyph->bitmap.buffer);
3412 // 	QString dbs;
3413 	for(int r(0); r < m_face->glyph->bitmap.rows; ++r)
3414 	{
3415 // 		dbs.clear();
3416 		for(int x(0); x < m_face->glyph->bitmap.width; ++x)
3417 		{
3418 			img.setPixel( x, r, *(cursor + x));
3419 // 			dbs += (*(cursor + x) > 0) ? "+" : ".";
3420 		}
3421 // 		qDebug()<<dbs;
3422 		cursor += m_face->glyph->bitmap.pitch;
3423 	}
3424 
3425 
3426 
3427 	return img;
3428 }
3429 
3430 
rawInfo()3431 FontInfoMap  FontItem::rawInfo()
3432 {
3433 	return FMFontDb::DB()->getInfoMap(m_path);
3434 }
3435 
3436 
3437 
3438 
3439 
3440 
shaperType() const3441 int FontItem::shaperType() const
3442 {
3443 	return m_shaperType;
3444 }
3445 
3446 
setShaperType(int theValue)3447 void FontItem::setShaperType ( int theValue )
3448 {
3449 	m_shaperType = theValue;
3450 }
3451 
glyphs(QString spec,double fsize)3452 GlyphList FontItem::glyphs ( QString spec, double fsize )
3453 {
3454 // 	qDebug()<<"glyphs ("<< spec.left(24) <<", "<<fsize<<" )";
3455 	FMHyphenator *hyph = typotek::getInstance()->getHyphenator();
3456 	GlyphList ret;
3457 	if ( spec.isEmpty() || fsize <= 0.0 )
3458 		return ret;
3459 	if( !ensureFace() )
3460 		return ret;
3461 	double scalefactor = fsize / m_face->units_per_EM  ;
3462 
3463 	QChar spaceChar(' ');
3464 	int startSpaceCount(0);
3465 	int endSpaceCount(0);
3466 	int specCount(spec.count());
3467 	for(int s(0); s < specCount; ++s)
3468 	{
3469 		if(spec.at(s) == spaceChar)
3470 			++startSpaceCount;
3471 		else
3472 			break;
3473 	}
3474 	if(startSpaceCount != specCount)
3475 	{
3476 		for(int s(specCount-1); s >= 0; --s)
3477 		{
3478 			if(spec.at(s) == spaceChar)
3479 				++endSpaceCount;
3480 			else
3481 				break;
3482 		}
3483 	}
3484 
3485 	QStringList stl(spec.split(spaceChar, QString::SkipEmptyParts));
3486 
3487 	QGraphicsPathItem *glyph = itemFromChar ( spaceChar.unicode() , fsize );
3488 	RenderedGlyph wSpace(glyph->data(GLYPH_DATA_GLYPH).toInt(),0, glyph->data(GLYPH_DATA_HADVANCE).toDouble() * scalefactor ,0,0,0,' ',false);
3489 	delete glyph;
3490 	for(int s(0); s < startSpaceCount; ++s)
3491 	{
3492 		ret << wSpace;
3493 	}
3494 	for(QStringList::const_iterator sIt(stl.constBegin());sIt != stl.constEnd(); ++ sIt)
3495 	{
3496 		if(sIt != stl.constBegin())
3497 		{
3498 			ret << wSpace;
3499 		}
3500 		HyphList hl;
3501 		if(hyph)
3502 		{
3503 			hl = hyph->hyphenate(*sIt) ;
3504 // 			if(hl.count())qDebug()<<"Hyph W C"<<*sIt<<hl.count();
3505 		}
3506 
3507 		for ( int i ( 0 ); i < (*sIt).count();++i )
3508 		{
3509 			glyph = itemFromChar ( (*sIt).at ( i ).unicode(), fsize );
3510 			if ( !glyph )
3511 			{
3512 				continue;
3513 			}
3514 			RenderedGlyph rg;
3515 			rg.glyph = glyph->data(GLYPH_DATA_GLYPH).toInt();
3516 			rg.log = i; // We are in a 1/1 relation
3517 			rg.lChar = (*sIt).at ( i ).unicode();
3518 			rg.xadvance =  glyph->data(GLYPH_DATA_HADVANCE).toDouble() * scalefactor;
3519 			rg.yadvance =  glyph->data(GLYPH_DATA_VADVANCE).toDouble() * scalefactor;
3520 			rg.xoffset = 0;
3521 			rg.yoffset = 0;
3522 			delete glyph;
3523 			if(hl.contains( i ))
3524 			{
3525 // 				qDebug()<<"H B A"<<i<<hl[i].first<<hl[i].second;
3526 				rg.isBreak = true;
3527 				QString addOnFirst;
3528 				QString addOnSecond;
3529 				addOnFirst =  hl[i].first.endsWith("-") ? "": "-";
3530 				addOnSecond = /*(*sIt).endsWith(".")?".":*/"";
3531 				QString bS(hl[i].first + addOnFirst);
3532 				for(int bI(0);bI<bS.count();++bI)
3533 				{
3534 // 					qDebug()<<"i bI a"<<i<<bI<<bS.at ( bI );
3535 					glyph = itemFromChar ( bS.at ( bI ).unicode(), fsize );
3536 					if ( !glyph )
3537 					{
3538 						continue;
3539 					}
3540 					RenderedGlyph bg;
3541 					bg.glyph = glyph->data(GLYPH_DATA_GLYPH).toInt();
3542 // 					bg.log = ; // We are in a 1/1 relation
3543 					bg.lChar = bS.at ( bI ).unicode();
3544 					bg.xadvance =  glyph->data(GLYPH_DATA_HADVANCE).toDouble() * scalefactor;
3545 					bg.yadvance =  glyph->data(GLYPH_DATA_VADVANCE).toDouble() * scalefactor;
3546 					bg.xoffset = 0;
3547 					bg.yoffset = 0;
3548 					delete glyph;
3549 					rg.hyphen.first << bg;
3550 
3551 				}
3552 				bS = hl[i].second + addOnSecond ;
3553 				for(int bI(0);bI<bS.count();++bI)
3554 				{
3555 					glyph = itemFromChar ( bS.at ( bI ).unicode(), fsize );
3556 					if ( !glyph )
3557 					{
3558 						continue;
3559 					}
3560 					RenderedGlyph bg;
3561 					bg.glyph = glyph->data(GLYPH_DATA_GLYPH).toInt();
3562 // 					bg.log = i; // We are in a 1/1 relation
3563 					bg.lChar = bS.at ( bI ).unicode();
3564 					bg.xadvance =  glyph->data(GLYPH_DATA_HADVANCE).toDouble() * scalefactor;
3565 					bg.yadvance =  glyph->data(GLYPH_DATA_VADVANCE).toDouble() * scalefactor;
3566 					bg.xoffset = 0;
3567 					bg.yoffset = 0;
3568 					delete glyph;
3569 					rg.hyphen.second << bg;
3570 
3571 				}
3572 
3573 			}
3574 			ret << rg;
3575 		}
3576 	}
3577 
3578 	for(int s(0); s < endSpaceCount; ++s)
3579 	{
3580 		ret << wSpace;
3581 	}
3582 	releaseFace();
3583 // 	qDebug()<<"EndOfGlyphs";
3584 	return ret;
3585 }
3586 
glyphs(QString spec,double fsize,OTFSet set)3587 GlyphList FontItem::glyphs(QString spec, double fsize, OTFSet set)
3588 {
3589 	FMHyphenator *hyph = typotek::getInstance()->getHyphenator();
3590 	GlyphList Gret;
3591 	if ( spec.isEmpty() || fsize <= 0.0 || !m_isOpenType) // enough :-)
3592 		return Gret;
3593 	if(!ensureFace())
3594 		return Gret;
3595 
3596 	otf = new FMOtf ( m_face, 0x10000 );
3597 	if ( !otf )
3598 	{
3599 		releaseFace();
3600 		return Gret;
3601 	}
3602 
3603 //	FMAltContext * actx ( FMAltContextLib::GetCurrentContext());
3604 //	int cword(0);
3605 //	int cchunk(0);
3606 	QStringList stl(spec.split(' ',QString::SkipEmptyParts));
3607 
3608 	double scalefactor = fsize / m_face->units_per_EM  ;
3609 
3610 	QGraphicsPathItem *glyph = itemFromChar ( QChar(' ').unicode() , fsize );
3611 	RenderedGlyph wSpace(glyph->data(GLYPH_DATA_GLYPH).toInt(),0, glyph->data(GLYPH_DATA_HADVANCE).toDouble() * scalefactor ,0,0,0,' ',false);
3612 	wSpace.lChar = 0x20;
3613 	delete glyph;
3614 	for(QStringList::const_iterator sIt(stl.constBegin());sIt != stl.constEnd(); ++ sIt)
3615 	{
3616 //		actx->setWord(cword);
3617 //		actx->setChunk(cchunk);
3618 //		actx->fileWord(*sIt);
3619 //		actx->fileChunk(*sIt);
3620 		if(sIt != stl.constBegin())
3621 		{
3622 			Gret << wSpace;
3623 		}
3624 		HyphList hl;
3625 		if(hyph)
3626 		{
3627 			hl = hyph->hyphenate(*sIt) ;
3628 // 			qDebug()<<"Hyph W C"<<*sIt<<hl.count();
3629 		}
3630 		GlyphList ret( otf->procstring ( *sIt , set ) );
3631 		// otf->procstring works in font unit, so...
3632 		for(int i(0); i < ret.count(); ++i)
3633 		{
3634 			ret[i].xadvance *= scalefactor;
3635 			ret[i].yadvance *= scalefactor;
3636 			ret[i].xoffset *= scalefactor;
3637 			ret[i].yoffset *= scalefactor;
3638 
3639 			if(hl.contains( ret[i].log ))
3640 			{
3641 // 				qDebug()<<"L R"<<hl[ret[i].log].first<<hl[ret[i].log].second;
3642 				ret[i].isBreak = true;
3643 				QString addOnFirst;
3644 				QString addOnSecond;
3645 				addOnFirst =  hl[i].first.endsWith("-") ? "": "-";
3646 // 				addOnSecond = (*sIt).endsWith(".")?".":"";
3647 //				actx->setChunk(++cchunk);
3648 //				actx->fileChunk( hl[ret[i].log].first + addOnFirst);
3649 				ret[i].hyphen.first = otf->procstring ( hl[ret[i].log].first + addOnFirst, set );
3650 				for(int f(0); f < ret[i].hyphen.first.count(); ++f)
3651 				{
3652 					ret[i].hyphen.first[f].xadvance *= scalefactor;
3653 					ret[i].hyphen.first[f].yadvance *= scalefactor;
3654 					ret[i].hyphen.first[f].xoffset *= scalefactor;
3655 					ret[i].hyphen.first[f].yoffset *= scalefactor;
3656 				}
3657 
3658 //				actx->setChunk(++cchunk);
3659 //				actx->fileChunk( hl[ret[i].log].second + addOnSecond );
3660 				ret[i].hyphen.second = otf->procstring ( hl[ret[i].log].second + addOnSecond, set );
3661 				for(int f(0); f < ret[i].hyphen.second.count(); ++f)
3662 				{
3663 					ret[i].hyphen.second[f].xadvance *= scalefactor;
3664 					ret[i].hyphen.second[f].yadvance *= scalefactor;
3665 					ret[i].hyphen.second[f].xoffset *= scalefactor;
3666 					ret[i].hyphen.second[f].yoffset *= scalefactor;
3667 				}
3668 			}
3669 		}
3670 
3671 		Gret << ret;
3672 //		cchunk = 0;
3673 //		++cword;
3674 
3675 	}
3676 	delete otf;
3677 	otf = 0;
3678 	releaseFace();
3679 	return Gret;
3680 }
3681 
glyphs(QString spec,double fsize,QString script)3682 GlyphList FontItem::glyphs(QString spec, double fsize, QString script)
3683 {
3684 	FMHyphenator *hyph = typotek::getInstance()->getHyphenator();
3685 	GlyphList Gret;
3686 	if ( spec.isEmpty() || fsize <= 0.0 || !m_isOpenType) // enough :-)
3687 		return Gret;
3688 	if(!ensureFace())
3689 		return Gret;
3690 
3691 	otf = new FMOtf ( m_face, 0x10000 );
3692 	if ( !otf )
3693 	{
3694 		releaseFace();
3695 		return Gret;
3696 	}
3697 	FMShaperFactory *shaperfactory = 0;
3698 //	switch(m_shaperType)
3699 //	{
3700 //		case FMShaperFactory::FONTMATRIX : shaperfactory = new FMShaperFactory(otf,script, FMShaperFactory::FONTMATRIX );
3701 //		break;
3702 //		case FMShaperFactory::HARFBUZZ : shaperfactory = new FMShaperFactory(otf,script, FMShaperFactory::HARFBUZZ );
3703 //		break;
3704 //		case FMShaperFactory::ICU : shaperfactory = new FMShaperFactory(otf,script, FMShaperFactory::ICU );
3705 //		break;
3706 //		case FMShaperFactory::M17N : shaperfactory = new FMShaperFactory(otf,script, FMShaperFactory::M17N );
3707 //		break;
3708 //		case FMShaperFactory::PANGO : shaperfactory = new FMShaperFactory(otf,script, FMShaperFactory::PANGO );
3709 //		break;
3710 //		case FMShaperFactory::OMEGA : shaperfactory = new FMShaperFactory(otf,script, FMShaperFactory::OMEGA);
3711 //		break;
3712 //		default : shaperfactory = new FMShaperFactory(otf,script, FMShaperFactory::FONTMATRIX );
3713 //	}
3714 	shaperfactory = new FMShaperFactory(otf,script, FMShaperFactory::ICU );
3715 
3716 
3717 	/// HYPHENATION
3718 
3719 	QStringList stl(spec.split(' ',QString::SkipEmptyParts));
3720 
3721 	double scalefactor = fsize / m_face->units_per_EM  ;
3722 	QGraphicsPathItem *glyph = itemFromChar ( QChar(' ').unicode() , fsize );
3723 	RenderedGlyph wSpace(glyph->data(GLYPH_DATA_GLYPH).toInt(),0, glyph->data(GLYPH_DATA_HADVANCE).toDouble() * scalefactor ,0,0,0,' ',false);
3724 	wSpace.lChar = 0x20;
3725 	delete glyph;
3726 
3727 	QMap<QString, GlyphList> cache;
3728 	for(QStringList::const_iterator sIt(stl.constBegin());sIt != stl.constEnd(); ++ sIt)
3729 	{
3730 		if(cache.contains(*sIt))
3731 		{
3732 			GlyphList ret( cache.value(*sIt) );
3733 			Gret <<  wSpace << ret;
3734 			continue;
3735 		}
3736 		if(sIt != stl.constBegin())
3737 		{
3738 			Gret << wSpace;
3739 		}
3740 		HyphList hl;
3741 		if(hyph)
3742 		{
3743 			hl = hyph->hyphenate(*sIt) ;
3744 		}
3745 
3746 		GlyphList ret( shaperfactory->doShape( *sIt ) );
3747 
3748 		for(int i(0); i < ret.count(); ++i)
3749 		{
3750 			ret[i].xadvance *= scalefactor;
3751 			ret[i].yadvance *= scalefactor;
3752 			ret[i].xoffset *= scalefactor;
3753 			ret[i].yoffset *= scalefactor;
3754 
3755 			if(hl.contains( ret[i].log ))
3756 			{
3757 				ret[i].isBreak = true;
3758 				QString addOnFirst;
3759 				QString addOnSecond;
3760 				addOnFirst =  hl[i].first.endsWith("-") ? "": "-";
3761 
3762 				ret[i].hyphen.first = shaperfactory->doShape ( hl[ret[i].log].first + addOnFirst );
3763 				for(int f(0); f < ret[i].hyphen.first.count(); ++f)
3764 				{
3765 					ret[i].hyphen.first[f].xadvance *= scalefactor;
3766 					ret[i].hyphen.first[f].yadvance *= scalefactor;
3767 					ret[i].hyphen.first[f].xoffset *= scalefactor;
3768 					ret[i].hyphen.first[f].yoffset *= scalefactor;
3769 				}
3770 
3771 				ret[i].hyphen.second = shaperfactory->doShape ( hl[ret[i].log].second + addOnSecond );
3772 				for(int f(0); f < ret[i].hyphen.second.count(); ++f)
3773 				{
3774 					ret[i].hyphen.second[f].xadvance *= scalefactor;
3775 					ret[i].hyphen.second[f].yadvance *= scalefactor;
3776 					ret[i].hyphen.second[f].xoffset *= scalefactor;
3777 					ret[i].hyphen.second[f].yoffset *= scalefactor;
3778 				}
3779 			}
3780 		}
3781 
3782 		Gret << ret;
3783 		cache[*sIt] = ret;
3784 
3785 
3786 	}
3787 
3788 	/// END OF HYPHENATION
3789 
3790 	delete shaperfactory;
3791 	delete otf;
3792 	otf = 0;
3793 	releaseFace();
3794 // 	foreach(RenderedGlyph g, Gret)
3795 // 	{
3796 // 		g.dump();
3797 // 	}
3798 	return Gret;
3799 }
3800 
3801 
getUnitPerEm()3802 double FontItem::getUnitPerEm()
3803 {
3804 	if(unitPerEm)
3805 		return unitPerEm;
3806 	if(ensureFace())
3807 	{
3808 		releaseFace();
3809 	}
3810 	return unitPerEm;
3811 }
3812 
3813 
3814 
getFTHintMode() const3815 unsigned int FontItem::getFTHintMode() const
3816 {
3817 	return m_FTHintMode;
3818 }
3819 
3820 
setFTHintMode(unsigned int theValue)3821 void FontItem::setFTHintMode ( unsigned int theValue )
3822 {
3823 	m_FTHintMode = theValue;
3824 }
3825 
3826 // here for migration purpose
dumpIntoDB()3827 void FontItem::dumpIntoDB()
3828 {
3829 	if ( !m_valid )
3830 		return;
3831 
3832 	FMFontDb *db ( FMFontDb::DB() );
3833 	db->initRecord ( m_path );
3834 
3835 	QString panString ( panose() );
3836 
3837 	QList<FMFontDb::Field> fl;
3838 	QVariantList vl;
3839 
3840 	fl << FMFontDb::Family
3841 	<< FMFontDb::Variant
3842 	<< FMFontDb::Name
3843 	<< FMFontDb::Type
3844 	<< FMFontDb::Panose;
3845 
3846 	vl << m_family
3847 	<< m_variant
3848 	<< m_name
3849 	<< m_type
3850 	<< panString;
3851 
3852 	db->setValues ( m_path,fl,vl );
3853 	db->setInfoMap ( m_path, moreInfo() );
3854 }
3855 
charmaps()3856 QStringList FontItem::charmaps()
3857 {
3858 	QStringList ret;
3859 	foreach(FT_Encoding e, m_charsets)
3860 	{
3861 		ret << FontStrings::Encoding(e);
3862 	}
3863 	return ret;
3864 }
3865 
renderSVG(const QString & s,const double & size)3866 QString FontItem::renderSVG(const QString & s, const double& size)
3867 {
3868 	if(!ensureFace())
3869 		return QString();
3870 
3871 	QString ret;
3872 	QString svg;
3873 	QTransform tf;
3874 	double pifs ( size );
3875 	double scaleFactor( pifs / unitPerEm );
3876 	double vertOffset ( pifs );
3877 	double horOffset ( 0 );
3878 	tf.translate ( horOffset , vertOffset );
3879 
3880 	foreach (const QChar& c, s )
3881 	{
3882 		{
3883 			QGraphicsPathItem * gpi ( itemFromChar ( c.unicode(), pifs ) );
3884 			if ( gpi )
3885 			{
3886 				GlyphToSVGHelper gtsh ( gpi->path(), tf );
3887 				svg += gtsh.getSVGPath();
3888 				horOffset += gpi->data(GLYPH_DATA_HADVANCE).toDouble() * scaleFactor;
3889 				tf.translate( gpi->data(GLYPH_DATA_HADVANCE).toDouble()  * scaleFactor,0 );
3890 				delete gpi;
3891 			}
3892 		}
3893 	}
3894 	QString openElem ( QString ( "<svg width=\"%1\" height=\"%2\"  xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">" )
3895 			.arg ( horOffset )
3896 			.arg ( m_face->height * scaleFactor ) );
3897 	ret += openElem;
3898 	ret += svg;
3899 	ret += "</svg>";
3900 
3901 	releaseFace();
3902 	return ret;
3903 }
3904 
getNamedChar(const QString & name)3905 unsigned short FontItem::getNamedChar(const QString & name)
3906 {
3907 	if(!ensureFace())
3908 		return 0;
3909 	unsigned short ret(0);
3910 
3911 	if(FT_HAS_GLYPH_NAMES( m_face ))
3912 	{
3913 		int bLen(256);
3914 		char* buffer(new char[bLen]);
3915 		FT_UInt index (1);
3916 		FT_UInt cc =  FT_Get_First_Char ( m_face, &index );
3917 		QString cname;
3918 		while ( index )
3919 		{
3920 			FT_Get_Glyph_Name(m_face, index , buffer, bLen);
3921 			cname = QString::fromLatin1(buffer);
3922 // 			qDebug()<<"NC"<<cname<<cc<<index;
3923 			if(0 == name.compare(cname))
3924 			{
3925 					ret = cc;
3926 					break;
3927 			}
3928 			cc = FT_Get_Next_Char ( m_face, cc, &index );
3929 		}
3930 		delete[] buffer;
3931 	}
3932 
3933 	releaseFace();
3934 	return ret;
3935 }
3936 
getNames()3937 QStringList FontItem::getNames()
3938 {
3939 	QStringList ret;
3940 	if(!ensureFace())
3941 		return ret;
3942 	if(FT_HAS_GLYPH_NAMES( m_face ))
3943 	{
3944 		int bLen(256);
3945 		char* buffer(new char[bLen]);
3946 		FT_UInt index (1);
3947 		FT_UInt cc =  FT_Get_First_Char ( m_face, &index );
3948 		QString cname;
3949 		while ( index )
3950 		{
3951 			FT_Get_Glyph_Name(m_face, index , buffer, bLen);
3952 			ret << QString::fromLatin1(buffer);
3953 			cc = FT_Get_Next_Char ( m_face, cc, &index );
3954 		}
3955 		delete[] buffer;
3956 	}
3957 	releaseFace();
3958 	return ret;
3959 }
3960 
exploreKernFeature()3961 void FontItem::exploreKernFeature()
3962 {
3963 	if(!ensureFace())
3964 		return;
3965 
3966 	FMKernFeature kf(m_face);
3967 
3968 	releaseFace();
3969 }
3970 
getUnicodeBuiltIn() const3971 bool FontItem::getUnicodeBuiltIn() const
3972 {
3973 	return m_unicodeBuiltIn;
3974 }
3975 
3976 
getCurrentEncoding() const3977 FT_Encoding FontItem::getCurrentEncoding() const
3978 {
3979 	return m_currentEncoding;
3980 }
3981 
3982 
getUnitPerEm() const3983 double FontItem::getUnitPerEm() const
3984 {
3985 	return unitPerEm;
3986 }
3987 
3988 
getCharsets() const3989 QList< FT_Encoding > FontItem::getCharsets() const
3990 {
3991 	return m_charsets;
3992 }
3993