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 <&#%6;> <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